2548: Support setting cargo features and resolve `default` features by default r=matklad a=oxalica

Fixes #2524 


Co-authored-by: oxalica <oxalicc@pm.me>
This commit is contained in:
bors[bot] 2019-12-14 11:57:49 +00:00 committed by GitHub
commit 7238037de4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 125 additions and 21 deletions

View File

@ -22,7 +22,7 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
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());

View File

@ -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<String, bool>,
/// 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(),
}
}
}

View File

@ -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),

View File

@ -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<String>,
}
#[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<CargoWorkspace> {
pub fn from_cargo_metadata(
cargo_toml: &Path,
cargo_features: &CargoFeatures,
) -> Result<CargoWorkspace> {
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);
}

View File

@ -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> {
ProjectWorkspace::discover_with_sysroot(path, true)
pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> {
ProjectWorkspace::discover_with_sysroot(path, true, cargo_features)
}
pub fn discover_with_sysroot(path: &Path, with_sysroot: bool) -> Result<ProjectWorkspace> {
pub fn discover_with_sysroot(
path: &Path,
with_sysroot: bool,
cargo_features: &CargoFeatures,
) -> Result<ProjectWorkspace> {
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 })

View File

@ -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": true,
"description": "Activate all available features"
},
"rust-analyzer.cargoFeatures.features": {
"type": "array",
"default": [],
"description": "List of features to activate"
}
}
},

View File

@ -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: true,
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,8 @@ 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 +156,53 @@ 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',
true,
);
}
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',
);
}
});
}
}
}

View File

@ -59,6 +59,7 @@ export class Server {
useClientWatching: Server.config.useClientWatching,
featureFlags: Server.config.featureFlags,
withSysroot: Server.config.withSysroot,
cargoFeatures: Server.config.cargoFeatures,
},
traceOutputChannel,
};