From af4eb266457eb784010da28d80535f9fd38d4d1e Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 13 Dec 2019 18:16:34 +0800 Subject: [PATCH] Support setting cargo features --- crates/ra_batch/src/lib.rs | 2 +- crates/ra_lsp_server/src/config.rs | 5 ++ crates/ra_lsp_server/src/main_loop.rs | 1 + .../ra_project_model/src/cargo_workspace.rs | 31 +++++++- crates/ra_project_model/src/lib.rs | 14 ++-- editors/code/package.json | 15 ++++ editors/code/src/config.ts | 70 +++++++++++++++---- editors/code/src/server.ts | 1 + 8 files changed, 118 insertions(+), 21 deletions(-) diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index 2c9645c00a..7744ba85a2 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs @@ -22,7 +22,7 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId { pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap)> { let root = std::env::current_dir()?.join(root); - let ws = ProjectWorkspace::discover(root.as_ref())?; + let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?; let project_roots = ws.to_roots(); let (sender, receiver) = unbounded(); let sender = Box::new(move |t| sender.send(t).unwrap()); diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs index 8045f3d60d..67942aa414 100644 --- a/crates/ra_lsp_server/src/config.rs +++ b/crates/ra_lsp_server/src/config.rs @@ -9,6 +9,7 @@ use rustc_hash::FxHashMap; +use ra_project_model::CargoFeatures; use serde::{Deserialize, Deserializer}; /// Client provided initialization options @@ -37,6 +38,9 @@ pub struct ServerConfig { /// Fine grained feature flags to disable specific features. pub feature_flags: FxHashMap, + + /// Cargo feature configurations. + pub cargo_features: CargoFeatures, } impl Default for ServerConfig { @@ -49,6 +53,7 @@ impl Default for ServerConfig { max_inlay_hint_length: None, with_sysroot: true, feature_flags: FxHashMap::default(), + cargo_features: Default::default(), } } } diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 158cac0be1..965e7c53c1 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -67,6 +67,7 @@ pub fn main_loop( let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( ws_root.as_path(), config.with_sysroot, + &config.cargo_features, ); match workspace { Ok(workspace) => loaded_workspaces.push(workspace), diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 351997dcdb..4a0437da32 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -6,6 +6,7 @@ use cargo_metadata::{CargoOpt, MetadataCommand}; use ra_arena::{impl_arena_id, Arena, RawId}; use ra_db::Edition; use rustc_hash::FxHashMap; +use serde::Deserialize; use crate::Result; @@ -23,6 +24,20 @@ pub struct CargoWorkspace { pub(crate) workspace_root: PathBuf, } +#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Default)] +#[serde(rename_all = "camelCase", default)] +pub struct CargoFeatures { + /// Do not activate the `default` feature. + pub no_default_features: bool, + + /// Activate all available features + pub all_features: bool, + + /// List of features to activate. + /// This will be ignored if `cargo_all_features` is true. + pub features: Vec, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Package(RawId); impl_arena_id!(Package); @@ -132,9 +147,21 @@ impl Target { } impl CargoWorkspace { - pub fn from_cargo_metadata(cargo_toml: &Path) -> Result { + pub fn from_cargo_metadata( + cargo_toml: &Path, + cargo_features: &CargoFeatures, + ) -> Result { let mut meta = MetadataCommand::new(); - meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); + meta.manifest_path(cargo_toml); + if cargo_features.all_features { + meta.features(CargoOpt::AllFeatures); + } else if cargo_features.no_default_features { + // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` + // https://github.com/oli-obk/cargo_metadata/issues/79 + meta.features(CargoOpt::NoDefaultFeatures); + } else { + meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); + } if let Some(parent) = cargo_toml.parent() { meta.current_dir(parent); } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 55ff4d6efc..d71b7031a8 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -18,7 +18,7 @@ use rustc_hash::FxHashMap; use serde_json::from_reader; pub use crate::{ - cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, + cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind}, json_project::JsonProject, sysroot::Sysroot, }; @@ -60,11 +60,15 @@ impl PackageRoot { } impl ProjectWorkspace { - pub fn discover(path: &Path) -> Result { - ProjectWorkspace::discover_with_sysroot(path, true) + pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result { + ProjectWorkspace::discover_with_sysroot(path, true, cargo_features) } - pub fn discover_with_sysroot(path: &Path, with_sysroot: bool) -> Result { + pub fn discover_with_sysroot( + path: &Path, + with_sysroot: bool, + cargo_features: &CargoFeatures, + ) -> Result { match find_rust_project_json(path) { Some(json_path) => { let file = File::open(json_path)?; @@ -73,7 +77,7 @@ impl ProjectWorkspace { } None => { let cargo_toml = find_cargo_toml(path)?; - let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; + let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features)?; let sysroot = if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() }; Ok(ProjectWorkspace::Cargo { cargo, sysroot }) diff --git a/editors/code/package.json b/editors/code/package.json index 7bc08ec31f..8ed95fda7e 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -278,6 +278,21 @@ "type": "number", "default": 20, "description": "Maximum length for inlay hints" + }, + "rust-analyzer.cargoFeatures.noDefaultFeatures": { + "type": "boolean", + "default": false, + "description": "Do not activate the `default` feature" + }, + "rust-analyzer.cargoFeatures.allFeatures": { + "type": "boolean", + "default": false, + "description": "Activate all available features" + }, + "rust-analyzer.cargoFeatures.features": { + "type": "array", + "default": [], + "description": "List of features to activate" } } }, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 2d3b6a54ea..6d709f7a85 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -15,6 +15,12 @@ export interface CargoWatchOptions { ignore: string[]; } +export interface CargoFeatures { + noDefaultFeatures: boolean; + allFeatures: boolean; + features: string[]; +} + export class Config { public highlightingOn = true; public rainbowHighlightingOn = false; @@ -35,8 +41,14 @@ export class Config { command: '', ignore: [], }; + public cargoFeatures: CargoFeatures = { + noDefaultFeatures: false, + allFeatures: false, + features: [], + }; private prevEnhancedTyping: null | boolean = null; + private prevCargoFeatures: null | CargoFeatures = null; constructor() { vscode.workspace.onDidChangeConfiguration(_ => @@ -47,6 +59,8 @@ export class Config { public userConfigChanged() { const config = vscode.workspace.getConfiguration('rust-analyzer'); + let requireReloadMessage = null; + if (config.has('highlightingOn')) { this.highlightingOn = config.get('highlightingOn') as boolean; } @@ -74,19 +88,7 @@ export class Config { } if (this.prevEnhancedTyping !== this.enableEnhancedTyping) { - const reloadAction = 'Reload now'; - vscode.window - .showInformationMessage( - 'Changing enhanced typing setting requires a reload', - reloadAction, - ) - .then(selectedAction => { - if (selectedAction === reloadAction) { - vscode.commands.executeCommand( - 'workbench.action.reloadWindow', - ); - } - }); + requireReloadMessage = 'Changing enhanced typing setting requires a reload'; this.prevEnhancedTyping = this.enableEnhancedTyping; } @@ -153,5 +155,47 @@ export class Config { if (config.has('withSysroot')) { this.withSysroot = config.get('withSysroot') || false; } + + if (config.has('cargoFeatures.noDefaultFeatures')) { + this.cargoFeatures.noDefaultFeatures = config.get( + 'cargoFeatures.noDefaultFeatures', + false, + ); + } + if (config.has('cargoFeatures.allFeatures')) { + this.cargoFeatures.allFeatures = config.get( + 'cargoFeatures.allFeatures', + false, + ); + } + if (config.has('cargoFeatures.features')) { + this.cargoFeatures.features = config.get( + 'cargoFeatures.features', + [], + ); + } + + if (this.prevCargoFeatures !== null && ( + this.cargoFeatures.allFeatures !== this.prevCargoFeatures.allFeatures || + this.cargoFeatures.noDefaultFeatures !== this.prevCargoFeatures.noDefaultFeatures || + this.cargoFeatures.features.length !== this.prevCargoFeatures.features.length || + this.cargoFeatures.features.some((v, i) => v !== this.prevCargoFeatures!.features[i]) + )) { + requireReloadMessage = 'Changing cargo features requires a reload'; + } + this.prevCargoFeatures = { ...this.cargoFeatures }; + + if (requireReloadMessage !== null) { + const reloadAction = 'Reload now'; + vscode.window + .showInformationMessage(requireReloadMessage, reloadAction) + .then(selectedAction => { + if (selectedAction === reloadAction) { + vscode.commands.executeCommand( + 'workbench.action.reloadWindow', + ); + } + }); + } } } diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts index 2fe45f1ed6..5ace1d0fae 100644 --- a/editors/code/src/server.ts +++ b/editors/code/src/server.ts @@ -59,6 +59,7 @@ export class Server { useClientWatching: Server.config.useClientWatching, featureFlags: Server.config.featureFlags, withSysroot: Server.config.withSysroot, + cargoFeatures: Server.config.cargoFeatures, }, traceOutputChannel, };