mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge pull request #3582 from kiljacken/out-dir-from-check
Update OUT_DIR based on `cargo check` output
This commit is contained in:
commit
ec1312ef38
18 changed files with 309 additions and 170 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1092,6 +1092,7 @@ dependencies = [
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"log",
|
"log",
|
||||||
"ra_arena",
|
"ra_arena",
|
||||||
|
"ra_cargo_watch",
|
||||||
"ra_cfg",
|
"ra_cfg",
|
||||||
"ra_db",
|
"ra_db",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
|
|
|
@ -9,8 +9,8 @@ use lsp_types::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
process::{Command, Stdio},
|
process::{Child, Command, Stdio},
|
||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
@ -246,43 +246,24 @@ enum CheckEvent {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WatchThread {
|
pub fn run_cargo(
|
||||||
fn dummy() -> WatchThread {
|
args: &[String],
|
||||||
WatchThread { handle: None, message_recv: never() }
|
current_dir: Option<&Path>,
|
||||||
|
on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
|
||||||
|
) -> Child {
|
||||||
|
let mut command = Command::new("cargo");
|
||||||
|
if let Some(current_dir) = current_dir {
|
||||||
|
command.current_dir(current_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(options: &CheckOptions, workspace_root: &PathBuf) -> WatchThread {
|
let mut child = command
|
||||||
let mut args: Vec<String> = vec![
|
.args(args)
|
||||||
options.command.clone(),
|
|
||||||
"--workspace".to_string(),
|
|
||||||
"--message-format=json".to_string(),
|
|
||||||
"--manifest-path".to_string(),
|
|
||||||
format!("{}/Cargo.toml", workspace_root.to_string_lossy()),
|
|
||||||
];
|
|
||||||
if options.all_targets {
|
|
||||||
args.push("--all-targets".to_string());
|
|
||||||
}
|
|
||||||
args.extend(options.args.iter().cloned());
|
|
||||||
|
|
||||||
let (message_send, message_recv) = unbounded();
|
|
||||||
let enabled = options.enable;
|
|
||||||
let handle = std::thread::spawn(move || {
|
|
||||||
if !enabled {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = Command::new("cargo")
|
|
||||||
.args(&args)
|
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("couldn't launch cargo");
|
.expect("couldn't launch cargo");
|
||||||
|
|
||||||
// If we trigger an error here, we will do so in the loop instead,
|
|
||||||
// which will break out of the loop, and continue the shutdown
|
|
||||||
let _ = message_send.send(CheckEvent::Begin);
|
|
||||||
|
|
||||||
// We manually read a line at a time, instead of using serde's
|
// We manually read a line at a time, instead of using serde's
|
||||||
// stream deserializers, because the deserializer cannot recover
|
// stream deserializers, because the deserializer cannot recover
|
||||||
// from an error, resulting in it getting stuck, because we try to
|
// from an error, resulting in it getting stuck, because we try to
|
||||||
|
@ -291,7 +272,7 @@ impl WatchThread {
|
||||||
// Because cargo only outputs one JSON object per line, we can
|
// Because cargo only outputs one JSON object per line, we can
|
||||||
// simply skip a line if it doesn't parse, which just ignores any
|
// simply skip a line if it doesn't parse, which just ignores any
|
||||||
// erroneus output.
|
// erroneus output.
|
||||||
let stdout = BufReader::new(command.stdout.take().unwrap());
|
let stdout = BufReader::new(child.stdout.take().unwrap());
|
||||||
for line in stdout.lines() {
|
for line in stdout.lines() {
|
||||||
let line = match line {
|
let line = match line {
|
||||||
Ok(line) => line,
|
Ok(line) => line,
|
||||||
|
@ -305,20 +286,51 @@ impl WatchThread {
|
||||||
let message = match message {
|
let message = match message {
|
||||||
Ok(message) => message,
|
Ok(message) => message,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!(
|
log::error!("Invalid json from cargo check, ignoring ({}): {:?} ", err, line);
|
||||||
"Invalid json from cargo check, ignoring ({}): {:?} ",
|
|
||||||
err,
|
|
||||||
line
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !on_message(message) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
child
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WatchThread {
|
||||||
|
fn dummy() -> WatchThread {
|
||||||
|
WatchThread { handle: None, message_recv: never() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(options: &CheckOptions, workspace_root: &Path) -> WatchThread {
|
||||||
|
let mut args: Vec<String> = vec![
|
||||||
|
options.command.clone(),
|
||||||
|
"--workspace".to_string(),
|
||||||
|
"--message-format=json".to_string(),
|
||||||
|
"--manifest-path".to_string(),
|
||||||
|
format!("{}/Cargo.toml", workspace_root.display()),
|
||||||
|
];
|
||||||
|
if options.all_targets {
|
||||||
|
args.push("--all-targets".to_string());
|
||||||
|
}
|
||||||
|
args.extend(options.args.iter().cloned());
|
||||||
|
|
||||||
|
let (message_send, message_recv) = unbounded();
|
||||||
|
let workspace_root = workspace_root.to_owned();
|
||||||
|
let handle = if options.enable {
|
||||||
|
Some(std::thread::spawn(move || {
|
||||||
|
// If we trigger an error here, we will do so in the loop instead,
|
||||||
|
// which will break out of the loop, and continue the shutdown
|
||||||
|
let _ = message_send.send(CheckEvent::Begin);
|
||||||
|
|
||||||
|
let mut child = run_cargo(&args, Some(&workspace_root), &mut |message| {
|
||||||
// Skip certain kinds of messages to only spend time on what's useful
|
// Skip certain kinds of messages to only spend time on what's useful
|
||||||
match &message {
|
match &message {
|
||||||
Message::CompilerArtifact(artifact) if artifact.fresh => continue,
|
Message::CompilerArtifact(artifact) if artifact.fresh => return true,
|
||||||
Message::BuildScriptExecuted(_) => continue,
|
Message::BuildScriptExecuted(_) => return true,
|
||||||
Message::Unknown => continue,
|
Message::Unknown => return true,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,22 +338,27 @@ impl WatchThread {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
// The send channel was closed, so we want to shutdown
|
// The send channel was closed, so we want to shutdown
|
||||||
break;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
// We can ignore any error here, as we are already in the progress
|
// We can ignore any error here, as we are already in the progress
|
||||||
// of shutting down.
|
// of shutting down.
|
||||||
let _ = message_send.send(CheckEvent::End);
|
let _ = message_send.send(CheckEvent::End);
|
||||||
|
|
||||||
// It is okay to ignore the result, as it only errors if the process is already dead
|
// It is okay to ignore the result, as it only errors if the process is already dead
|
||||||
let _ = command.kill();
|
let _ = child.kill();
|
||||||
|
|
||||||
// Again, we don't care about the exit status so just ignore the result
|
// Again, we don't care about the exit status so just ignore the result
|
||||||
let _ = command.wait();
|
let _ = child.wait();
|
||||||
});
|
}))
|
||||||
WatchThread { handle: Some(handle), message_recv }
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
WatchThread { handle, message_recv }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
|
//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
|
||||||
//! actual IO is done and lowered to input.
|
//! actual IO is done and lowered to input.
|
||||||
|
|
||||||
use std::{fmt, ops, str::FromStr};
|
use std::{
|
||||||
|
fmt, ops,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
use ra_cfg::CfgOptions;
|
use ra_cfg::CfgOptions;
|
||||||
use ra_syntax::SmolStr;
|
use ra_syntax::SmolStr;
|
||||||
|
@ -144,7 +148,7 @@ pub struct Env {
|
||||||
// crate. We store a map to allow remap it to ExternSourceId
|
// crate. We store a map to allow remap it to ExternSourceId
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ExternSource {
|
pub struct ExternSource {
|
||||||
extern_paths: FxHashMap<String, ExternSourceId>,
|
extern_paths: FxHashMap<PathBuf, ExternSourceId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -294,13 +298,10 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternSource {
|
impl ExternSource {
|
||||||
pub fn extern_path(&self, path: &str) -> Option<(ExternSourceId, RelativePathBuf)> {
|
pub fn extern_path(&self, path: impl AsRef<Path>) -> Option<(ExternSourceId, RelativePathBuf)> {
|
||||||
|
let path = path.as_ref();
|
||||||
self.extern_paths.iter().find_map(|(root_path, id)| {
|
self.extern_paths.iter().find_map(|(root_path, id)| {
|
||||||
if path.starts_with(root_path) {
|
if let Ok(rel_path) = path.strip_prefix(root_path) {
|
||||||
let mut rel_path = &path[root_path.len()..];
|
|
||||||
if rel_path.starts_with("/") {
|
|
||||||
rel_path = &rel_path[1..];
|
|
||||||
}
|
|
||||||
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
||||||
Some((id.clone(), rel_path))
|
Some((id.clone(), rel_path))
|
||||||
} else {
|
} else {
|
||||||
|
@ -309,8 +310,8 @@ impl ExternSource {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_extern_path(&mut self, root_path: &str, root: ExternSourceId) {
|
pub fn set_extern_path(&mut self, root_path: &Path, root: ExternSourceId) {
|
||||||
self.extern_paths.insert(root_path.to_owned(), root);
|
self.extern_paths.insert(root_path.to_path_buf(), root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ cargo_metadata = "0.9.1"
|
||||||
ra_arena = { path = "../ra_arena" }
|
ra_arena = { path = "../ra_arena" }
|
||||||
ra_db = { path = "../ra_db" }
|
ra_db = { path = "../ra_db" }
|
||||||
ra_cfg = { path = "../ra_cfg" }
|
ra_cfg = { path = "../ra_cfg" }
|
||||||
|
ra_cargo_watch = { path = "../ra_cargo_watch" }
|
||||||
|
|
||||||
serde = { version = "1.0.104", features = ["derive"] }
|
serde = { version = "1.0.104", features = ["derive"] }
|
||||||
serde_json = "1.0.48"
|
serde_json = "1.0.48"
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use cargo_metadata::{CargoOpt, MetadataCommand};
|
use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId};
|
||||||
use ra_arena::{impl_arena_id, Arena, RawId};
|
use ra_arena::{impl_arena_id, Arena, RawId};
|
||||||
|
use ra_cargo_watch::run_cargo;
|
||||||
use ra_db::Edition;
|
use ra_db::Edition;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -35,11 +36,19 @@ pub struct CargoFeatures {
|
||||||
/// List of features to activate.
|
/// List of features to activate.
|
||||||
/// This will be ignored if `cargo_all_features` is true.
|
/// This will be ignored if `cargo_all_features` is true.
|
||||||
pub features: Vec<String>,
|
pub features: Vec<String>,
|
||||||
|
|
||||||
|
/// Runs cargo check on launch to figure out the correct values of OUT_DIR
|
||||||
|
pub load_out_dirs_from_check: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CargoFeatures {
|
impl Default for CargoFeatures {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
|
CargoFeatures {
|
||||||
|
no_default_features: false,
|
||||||
|
all_features: true,
|
||||||
|
features: Vec::new(),
|
||||||
|
load_out_dirs_from_check: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +69,7 @@ struct PackageData {
|
||||||
dependencies: Vec<PackageDependency>,
|
dependencies: Vec<PackageDependency>,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
features: Vec<String>,
|
features: Vec<String>,
|
||||||
|
out_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -131,6 +141,9 @@ impl Package {
|
||||||
) -> impl Iterator<Item = &'a PackageDependency> + 'a {
|
) -> impl Iterator<Item = &'a PackageDependency> + 'a {
|
||||||
ws.packages[self].dependencies.iter()
|
ws.packages[self].dependencies.iter()
|
||||||
}
|
}
|
||||||
|
pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> {
|
||||||
|
ws.packages[self].out_dir.as_ref().map(PathBuf::as_path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
|
@ -173,6 +186,12 @@ impl CargoWorkspace {
|
||||||
let meta = meta.exec().with_context(|| {
|
let meta = meta.exec().with_context(|| {
|
||||||
format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
|
format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let mut out_dir_by_id = FxHashMap::default();
|
||||||
|
if cargo_features.load_out_dirs_from_check {
|
||||||
|
out_dir_by_id = load_out_dirs(cargo_toml, cargo_features);
|
||||||
|
}
|
||||||
|
|
||||||
let mut pkg_by_id = FxHashMap::default();
|
let mut pkg_by_id = FxHashMap::default();
|
||||||
let mut packages = Arena::default();
|
let mut packages = Arena::default();
|
||||||
let mut targets = Arena::default();
|
let mut targets = Arena::default();
|
||||||
|
@ -193,6 +212,7 @@ impl CargoWorkspace {
|
||||||
edition,
|
edition,
|
||||||
dependencies: Vec::new(),
|
dependencies: Vec::new(),
|
||||||
features: Vec::new(),
|
features: Vec::new(),
|
||||||
|
out_dir: out_dir_by_id.get(&id).cloned(),
|
||||||
});
|
});
|
||||||
let pkg_data = &mut packages[pkg];
|
let pkg_data = &mut packages[pkg];
|
||||||
pkg_by_id.insert(id, pkg);
|
pkg_by_id.insert(id, pkg);
|
||||||
|
@ -252,3 +272,46 @@ impl CargoWorkspace {
|
||||||
&self.workspace_root
|
&self.workspace_root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_out_dirs(
|
||||||
|
cargo_toml: &Path,
|
||||||
|
cargo_features: &CargoFeatures,
|
||||||
|
) -> FxHashMap<PackageId, PathBuf> {
|
||||||
|
let mut args: Vec<String> = vec![
|
||||||
|
"check".to_string(),
|
||||||
|
"--message-format=json".to_string(),
|
||||||
|
"--manifest-path".to_string(),
|
||||||
|
format!("{}", cargo_toml.display()),
|
||||||
|
];
|
||||||
|
|
||||||
|
if cargo_features.all_features {
|
||||||
|
args.push("--all-features".to_string());
|
||||||
|
} else if cargo_features.no_default_features {
|
||||||
|
// FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
|
||||||
|
// https://github.com/oli-obk/cargo_metadata/issues/79
|
||||||
|
args.push("--no-default-features".to_string());
|
||||||
|
} else if !cargo_features.features.is_empty() {
|
||||||
|
for feature in &cargo_features.features {
|
||||||
|
args.push(feature.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = FxHashMap::default();
|
||||||
|
let mut child = run_cargo(&args, cargo_toml.parent(), &mut |message| {
|
||||||
|
match message {
|
||||||
|
Message::BuildScriptExecuted(message) => {
|
||||||
|
let package_id = message.package_id;
|
||||||
|
let out_dir = message.out_dir;
|
||||||
|
res.insert(package_id, out_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::CompilerArtifact(_) => (),
|
||||||
|
Message::CompilerMessage(_) => (),
|
||||||
|
Message::Unknown => (),
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = child.wait();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub struct Crate {
|
||||||
pub(crate) deps: Vec<Dep>,
|
pub(crate) deps: Vec<Dep>,
|
||||||
pub(crate) atom_cfgs: FxHashSet<String>,
|
pub(crate) atom_cfgs: FxHashSet<String>,
|
||||||
pub(crate) key_value_cfgs: FxHashMap<String, String>,
|
pub(crate) key_value_cfgs: FxHashMap<String, String>,
|
||||||
|
pub(crate) out_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize)]
|
#[derive(Clone, Copy, Debug, Deserialize)]
|
||||||
|
|
|
@ -150,6 +150,29 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn out_dirs(&self) -> Vec<PathBuf> {
|
||||||
|
match self {
|
||||||
|
ProjectWorkspace::Json { project } => {
|
||||||
|
let mut out_dirs = Vec::with_capacity(project.crates.len());
|
||||||
|
for krate in &project.crates {
|
||||||
|
if let Some(out_dir) = &krate.out_dir {
|
||||||
|
out_dirs.push(out_dir.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_dirs
|
||||||
|
}
|
||||||
|
ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => {
|
||||||
|
let mut out_dirs = Vec::with_capacity(cargo.packages().len());
|
||||||
|
for pkg in cargo.packages() {
|
||||||
|
if let Some(out_dir) = pkg.out_dir(&cargo) {
|
||||||
|
out_dirs.push(out_dir.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_dirs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn n_packages(&self) -> usize {
|
pub fn n_packages(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
ProjectWorkspace::Json { project } => project.crates.len(),
|
ProjectWorkspace::Json { project } => project.crates.len(),
|
||||||
|
@ -162,7 +185,7 @@ impl ProjectWorkspace {
|
||||||
pub fn to_crate_graph(
|
pub fn to_crate_graph(
|
||||||
&self,
|
&self,
|
||||||
default_cfg_options: &CfgOptions,
|
default_cfg_options: &CfgOptions,
|
||||||
outdirs: &FxHashMap<String, (ExternSourceId, String)>,
|
extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>,
|
||||||
load: &mut dyn FnMut(&Path) -> Option<FileId>,
|
load: &mut dyn FnMut(&Path) -> Option<FileId>,
|
||||||
) -> CrateGraph {
|
) -> CrateGraph {
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
|
@ -187,6 +210,16 @@ impl ProjectWorkspace {
|
||||||
opts
|
opts
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut env = Env::default();
|
||||||
|
let mut extern_source = ExternSource::default();
|
||||||
|
if let Some(out_dir) = &krate.out_dir {
|
||||||
|
// FIXME: We probably mangle non UTF-8 paths here, figure out a better solution
|
||||||
|
env.set("OUT_DIR", out_dir.to_string_lossy().to_string());
|
||||||
|
if let Some(&extern_source_id) = extern_source_roots.get(out_dir) {
|
||||||
|
extern_source.set_extern_path(&out_dir, extern_source_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
|
// FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
|
||||||
crates.insert(
|
crates.insert(
|
||||||
crate_id,
|
crate_id,
|
||||||
|
@ -196,8 +229,8 @@ impl ProjectWorkspace {
|
||||||
// FIXME json definitions can store the crate name
|
// FIXME json definitions can store the crate name
|
||||||
None,
|
None,
|
||||||
cfg_options,
|
cfg_options,
|
||||||
Env::default(),
|
env,
|
||||||
Default::default(),
|
extern_source,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -235,13 +268,8 @@ impl ProjectWorkspace {
|
||||||
opts
|
opts
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut env = Env::default();
|
let env = Env::default();
|
||||||
let mut extern_source = ExternSource::default();
|
let extern_source = ExternSource::default();
|
||||||
if let Some((id, path)) = outdirs.get(krate.name(&sysroot)) {
|
|
||||||
env.set("OUT_DIR", path.clone());
|
|
||||||
extern_source.set_extern_path(&path, *id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let crate_id = crate_graph.add_crate_root(
|
let crate_id = crate_graph.add_crate_root(
|
||||||
file_id,
|
file_id,
|
||||||
Edition::Edition2018,
|
Edition::Edition2018,
|
||||||
|
@ -292,9 +320,12 @@ impl ProjectWorkspace {
|
||||||
};
|
};
|
||||||
let mut env = Env::default();
|
let mut env = Env::default();
|
||||||
let mut extern_source = ExternSource::default();
|
let mut extern_source = ExternSource::default();
|
||||||
if let Some((id, path)) = outdirs.get(pkg.name(&cargo)) {
|
if let Some(out_dir) = pkg.out_dir(cargo) {
|
||||||
env.set("OUT_DIR", path.clone());
|
// FIXME: We probably mangle non UTF-8 paths here, figure out a better solution
|
||||||
extern_source.set_extern_path(&path, *id);
|
env.set("OUT_DIR", out_dir.to_string_lossy().to_string());
|
||||||
|
if let Some(&extern_source_id) = extern_source_roots.get(out_dir) {
|
||||||
|
extern_source.set_extern_path(&out_dir, extern_source_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let crate_id = crate_graph.add_crate_root(
|
let crate_id = crate_graph.add_crate_root(
|
||||||
file_id,
|
file_id,
|
||||||
|
|
|
@ -28,10 +28,12 @@ pub(crate) enum Command {
|
||||||
only: Option<String>,
|
only: Option<String>,
|
||||||
with_deps: bool,
|
with_deps: bool,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
load_output_dirs: bool,
|
||||||
},
|
},
|
||||||
Bench {
|
Bench {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
what: BenchWhat,
|
what: BenchWhat,
|
||||||
|
load_output_dirs: bool,
|
||||||
},
|
},
|
||||||
RunServer,
|
RunServer,
|
||||||
Version,
|
Version,
|
||||||
|
@ -138,6 +140,7 @@ USAGE:
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
--memory-usage
|
--memory-usage
|
||||||
|
--load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
|
||||||
-v, --verbose
|
-v, --verbose
|
||||||
-q, --quiet
|
-q, --quiet
|
||||||
|
|
||||||
|
@ -154,6 +157,7 @@ ARGS:
|
||||||
let memory_usage = matches.contains("--memory-usage");
|
let memory_usage = matches.contains("--memory-usage");
|
||||||
let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
|
let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
|
||||||
let with_deps: bool = matches.contains("--with-deps");
|
let with_deps: bool = matches.contains("--with-deps");
|
||||||
|
let load_output_dirs = matches.contains("--load-output-dirs");
|
||||||
let path = {
|
let path = {
|
||||||
let mut trailing = matches.free()?;
|
let mut trailing = matches.free()?;
|
||||||
if trailing.len() != 1 {
|
if trailing.len() != 1 {
|
||||||
|
@ -162,7 +166,7 @@ ARGS:
|
||||||
trailing.pop().unwrap().into()
|
trailing.pop().unwrap().into()
|
||||||
};
|
};
|
||||||
|
|
||||||
Command::Stats { randomize, memory_usage, only, with_deps, path }
|
Command::Stats { randomize, memory_usage, only, with_deps, path, load_output_dirs }
|
||||||
}
|
}
|
||||||
"analysis-bench" => {
|
"analysis-bench" => {
|
||||||
if matches.contains(["-h", "--help"]) {
|
if matches.contains(["-h", "--help"]) {
|
||||||
|
@ -175,6 +179,7 @@ USAGE:
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
|
--load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
|
||||||
-v, --verbose
|
-v, --verbose
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
@ -201,7 +206,8 @@ ARGS:
|
||||||
"exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
|
"exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
Command::Bench { path, what }
|
let load_output_dirs = matches.contains("--load-output-dirs");
|
||||||
|
Command::Bench { path, what, load_output_dirs }
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|
|
@ -19,19 +19,25 @@ fn main() -> Result<()> {
|
||||||
args::Command::Parse { no_dump } => cli::parse(no_dump)?,
|
args::Command::Parse { no_dump } => cli::parse(no_dump)?,
|
||||||
args::Command::Symbols => cli::symbols()?,
|
args::Command::Symbols => cli::symbols()?,
|
||||||
args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
|
args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
|
||||||
args::Command::Stats { randomize, memory_usage, only, with_deps, path } => {
|
args::Command::Stats {
|
||||||
cli::analysis_stats(
|
randomize,
|
||||||
|
memory_usage,
|
||||||
|
only,
|
||||||
|
with_deps,
|
||||||
|
path,
|
||||||
|
load_output_dirs,
|
||||||
|
} => cli::analysis_stats(
|
||||||
args.verbosity,
|
args.verbosity,
|
||||||
memory_usage,
|
memory_usage,
|
||||||
path.as_ref(),
|
path.as_ref(),
|
||||||
only.as_ref().map(String::as_ref),
|
only.as_ref().map(String::as_ref),
|
||||||
with_deps,
|
with_deps,
|
||||||
randomize,
|
randomize,
|
||||||
)?
|
load_output_dirs,
|
||||||
}
|
)?,
|
||||||
|
|
||||||
args::Command::Bench { path, what } => {
|
args::Command::Bench { path, what, load_output_dirs } => {
|
||||||
cli::analysis_bench(args.verbosity, path.as_ref(), what)?
|
cli::analysis_bench(args.verbosity, path.as_ref(), what, load_output_dirs)?
|
||||||
}
|
}
|
||||||
|
|
||||||
args::Command::RunServer => run_server()?,
|
args::Command::RunServer => run_server()?,
|
||||||
|
|
|
@ -42,12 +42,17 @@ fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
|
||||||
Ok((&s[..idx], &s[idx + 1..]))
|
Ok((&s[..idx], &s[idx + 1..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analysis_bench(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Result<()> {
|
pub fn analysis_bench(
|
||||||
|
verbosity: Verbosity,
|
||||||
|
path: &Path,
|
||||||
|
what: BenchWhat,
|
||||||
|
load_output_dirs: bool,
|
||||||
|
) -> Result<()> {
|
||||||
ra_prof::init();
|
ra_prof::init();
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
eprint!("loading: ");
|
eprint!("loading: ");
|
||||||
let (mut host, roots) = load_cargo(path)?;
|
let (mut host, roots) = load_cargo(path, load_output_dirs)?;
|
||||||
let db = host.raw_database();
|
let db = host.raw_database();
|
||||||
eprintln!("{:?}\n", start.elapsed());
|
eprintln!("{:?}\n", start.elapsed());
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,10 @@ pub fn analysis_stats(
|
||||||
only: Option<&str>,
|
only: Option<&str>,
|
||||||
with_deps: bool,
|
with_deps: bool,
|
||||||
randomize: bool,
|
randomize: bool,
|
||||||
|
load_output_dirs: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let db_load_time = Instant::now();
|
let db_load_time = Instant::now();
|
||||||
let (mut host, roots) = load_cargo(path)?;
|
let (mut host, roots) = load_cargo(path, load_output_dirs)?;
|
||||||
let db = host.raw_database();
|
let db = host.raw_database();
|
||||||
println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
|
println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
|
||||||
let analysis_time = Instant::now();
|
let analysis_time = Instant::now();
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
//! Loads a Cargo project into a static instance of analysis, without support
|
//! Loads a Cargo project into a static instance of analysis, without support
|
||||||
//! for incorporating changes.
|
//! for incorporating changes.
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossbeam_channel::{unbounded, Receiver};
|
use crossbeam_channel::{unbounded, Receiver};
|
||||||
use ra_db::{CrateGraph, FileId, SourceRootId};
|
use ra_db::{ExternSourceId, FileId, SourceRootId};
|
||||||
use ra_ide::{AnalysisChange, AnalysisHost};
|
use ra_ide::{AnalysisChange, AnalysisHost};
|
||||||
use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace};
|
use ra_project_model::{get_rustc_cfg_options, CargoFeatures, PackageRoot, ProjectWorkspace};
|
||||||
use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
|
use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
|
@ -22,10 +22,21 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
|
||||||
|
|
||||||
pub(crate) fn load_cargo(
|
pub(crate) fn load_cargo(
|
||||||
root: &Path,
|
root: &Path,
|
||||||
|
load_out_dirs_from_check: bool,
|
||||||
) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
|
) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
|
||||||
let root = std::env::current_dir()?.join(root);
|
let root = std::env::current_dir()?.join(root);
|
||||||
let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?;
|
let ws = ProjectWorkspace::discover(
|
||||||
let project_roots = ws.to_roots();
|
root.as_ref(),
|
||||||
|
&CargoFeatures { load_out_dirs_from_check, ..Default::default() },
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut extern_dirs = FxHashSet::default();
|
||||||
|
extern_dirs.extend(ws.out_dirs());
|
||||||
|
|
||||||
|
let mut project_roots = ws.to_roots();
|
||||||
|
project_roots
|
||||||
|
.extend(extern_dirs.iter().map(|path| PackageRoot::new(path.to_path_buf(), false)));
|
||||||
|
|
||||||
let (sender, receiver) = unbounded();
|
let (sender, receiver) = unbounded();
|
||||||
let sender = Box::new(move |t| sender.send(t).unwrap());
|
let sender = Box::new(move |t| sender.send(t).unwrap());
|
||||||
let (mut vfs, roots) = Vfs::new(
|
let (mut vfs, roots) = Vfs::new(
|
||||||
|
@ -44,24 +55,6 @@ pub(crate) fn load_cargo(
|
||||||
Watch(false),
|
Watch(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: cfg options?
|
|
||||||
let default_cfg_options = {
|
|
||||||
let mut opts = get_rustc_cfg_options();
|
|
||||||
opts.insert_atom("test".into());
|
|
||||||
opts.insert_atom("debug_assertion".into());
|
|
||||||
opts
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: outdirs?
|
|
||||||
let outdirs = FxHashMap::default();
|
|
||||||
|
|
||||||
let crate_graph = ws.to_crate_graph(&default_cfg_options, &outdirs, &mut |path: &Path| {
|
|
||||||
let vfs_file = vfs.load(path);
|
|
||||||
log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
|
|
||||||
vfs_file.map(vfs_file_to_id)
|
|
||||||
});
|
|
||||||
log::debug!("crate graph: {:?}", crate_graph);
|
|
||||||
|
|
||||||
let source_roots = roots
|
let source_roots = roots
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&vfs_root| {
|
.map(|&vfs_root| {
|
||||||
|
@ -74,23 +67,24 @@ pub(crate) fn load_cargo(
|
||||||
(source_root_id, project_root)
|
(source_root_id, project_root)
|
||||||
})
|
})
|
||||||
.collect::<FxHashMap<_, _>>();
|
.collect::<FxHashMap<_, _>>();
|
||||||
let host = load(&source_roots, crate_graph, &mut vfs, receiver);
|
let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs);
|
||||||
Ok((host, source_roots))
|
Ok((host, source_roots))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load(
|
pub(crate) fn load(
|
||||||
source_roots: &FxHashMap<SourceRootId, PackageRoot>,
|
source_roots: &FxHashMap<SourceRootId, PackageRoot>,
|
||||||
crate_graph: CrateGraph,
|
ws: ProjectWorkspace,
|
||||||
vfs: &mut Vfs,
|
vfs: &mut Vfs,
|
||||||
receiver: Receiver<VfsTask>,
|
receiver: Receiver<VfsTask>,
|
||||||
|
extern_dirs: FxHashSet<PathBuf>,
|
||||||
) -> AnalysisHost {
|
) -> AnalysisHost {
|
||||||
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
|
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
|
||||||
let mut host = AnalysisHost::new(lru_cap);
|
let mut host = AnalysisHost::new(lru_cap);
|
||||||
let mut analysis_change = AnalysisChange::new();
|
let mut analysis_change = AnalysisChange::new();
|
||||||
analysis_change.set_crate_graph(crate_graph);
|
|
||||||
|
|
||||||
// wait until Vfs has loaded all roots
|
// wait until Vfs has loaded all roots
|
||||||
let mut roots_loaded = FxHashSet::default();
|
let mut roots_loaded = FxHashSet::default();
|
||||||
|
let mut extern_source_roots = FxHashMap::default();
|
||||||
for task in receiver {
|
for task in receiver {
|
||||||
vfs.handle_task(task);
|
vfs.handle_task(task);
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
|
@ -110,6 +104,11 @@ pub(crate) fn load(
|
||||||
source_roots[&source_root_id].path().display().to_string(),
|
source_roots[&source_root_id].path().display().to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let vfs_root_path = vfs.root2path(root);
|
||||||
|
if extern_dirs.contains(&vfs_root_path) {
|
||||||
|
extern_source_roots.insert(vfs_root_path, ExternSourceId(root.0));
|
||||||
|
}
|
||||||
|
|
||||||
let mut file_map = FxHashMap::default();
|
let mut file_map = FxHashMap::default();
|
||||||
for (vfs_file, path, text) in files {
|
for (vfs_file, path, text) in files {
|
||||||
let file_id = vfs_file_to_id(vfs_file);
|
let file_id = vfs_file_to_id(vfs_file);
|
||||||
|
@ -136,6 +135,23 @@ pub(crate) fn load(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: cfg options?
|
||||||
|
let default_cfg_options = {
|
||||||
|
let mut opts = get_rustc_cfg_options();
|
||||||
|
opts.insert_atom("test".into());
|
||||||
|
opts.insert_atom("debug_assertion".into());
|
||||||
|
opts
|
||||||
|
};
|
||||||
|
|
||||||
|
let crate_graph =
|
||||||
|
ws.to_crate_graph(&default_cfg_options, &extern_source_roots, &mut |path: &Path| {
|
||||||
|
let vfs_file = vfs.load(path);
|
||||||
|
log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
|
||||||
|
vfs_file.map(vfs_file_to_id)
|
||||||
|
});
|
||||||
|
log::debug!("crate graph: {:?}", crate_graph);
|
||||||
|
analysis_change.set_crate_graph(crate_graph);
|
||||||
|
|
||||||
host.apply_change(analysis_change);
|
host.apply_change(analysis_change);
|
||||||
host
|
host
|
||||||
}
|
}
|
||||||
|
@ -149,7 +165,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_loading_rust_analyzer() {
|
fn test_loading_rust_analyzer() {
|
||||||
let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
|
let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
|
||||||
let (host, _roots) = load_cargo(path).unwrap();
|
let (host, _roots) = load_cargo(path, false).unwrap();
|
||||||
let n_crates = Crate::all(host.raw_database()).len();
|
let n_crates = Crate::all(host.raw_database()).len();
|
||||||
// RA has quite a few crates, but the exact count doesn't matter
|
// RA has quite a few crates, but the exact count doesn't matter
|
||||||
assert!(n_crates > 20);
|
assert!(n_crates > 20);
|
||||||
|
|
|
@ -48,9 +48,6 @@ pub struct ServerConfig {
|
||||||
/// Fine grained feature flags to disable specific features.
|
/// Fine grained feature flags to disable specific features.
|
||||||
pub feature_flags: FxHashMap<String, bool>,
|
pub feature_flags: FxHashMap<String, bool>,
|
||||||
|
|
||||||
/// Fine grained controls for additional `OUT_DIR` env variables
|
|
||||||
pub additional_out_dirs: FxHashMap<String, String>,
|
|
||||||
|
|
||||||
pub rustfmt_args: Vec<String>,
|
pub rustfmt_args: Vec<String>,
|
||||||
|
|
||||||
/// Cargo feature configurations.
|
/// Cargo feature configurations.
|
||||||
|
@ -76,7 +73,6 @@ impl Default for ServerConfig {
|
||||||
cargo_watch_all_targets: true,
|
cargo_watch_all_targets: true,
|
||||||
with_sysroot: true,
|
with_sysroot: true,
|
||||||
feature_flags: FxHashMap::default(),
|
feature_flags: FxHashMap::default(),
|
||||||
additional_out_dirs: FxHashMap::default(),
|
|
||||||
cargo_features: Default::default(),
|
cargo_features: Default::default(),
|
||||||
rustfmt_args: Vec::new(),
|
rustfmt_args: Vec::new(),
|
||||||
vscode_lldb: false,
|
vscode_lldb: false,
|
||||||
|
|
|
@ -204,7 +204,6 @@ pub fn main_loop(
|
||||||
Watch(!config.use_client_watching),
|
Watch(!config.use_client_watching),
|
||||||
options,
|
options,
|
||||||
feature_flags,
|
feature_flags,
|
||||||
config.additional_out_dirs,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,6 @@ impl WorldState {
|
||||||
watch: Watch,
|
watch: Watch,
|
||||||
options: Options,
|
options: Options,
|
||||||
feature_flags: FeatureFlags,
|
feature_flags: FeatureFlags,
|
||||||
additional_out_dirs: FxHashMap<String, String>,
|
|
||||||
) -> WorldState {
|
) -> WorldState {
|
||||||
let mut change = AnalysisChange::new();
|
let mut change = AnalysisChange::new();
|
||||||
|
|
||||||
|
@ -105,11 +104,14 @@ impl WorldState {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let extern_dirs: FxHashSet<_> =
|
let mut extern_dirs = FxHashSet::default();
|
||||||
additional_out_dirs.iter().map(|(_, path)| (PathBuf::from(path))).collect();
|
for ws in workspaces.iter() {
|
||||||
|
extern_dirs.extend(ws.out_dirs());
|
||||||
|
}
|
||||||
|
|
||||||
let mut extern_source_roots = FxHashMap::default();
|
let mut extern_source_roots = FxHashMap::default();
|
||||||
|
|
||||||
roots.extend(additional_out_dirs.iter().map(|(_, path)| {
|
roots.extend(extern_dirs.iter().map(|path| {
|
||||||
let mut filter = RustPackageFilterBuilder::default().set_member(false);
|
let mut filter = RustPackageFilterBuilder::default().set_member(false);
|
||||||
for glob in exclude_globs.iter() {
|
for glob in exclude_globs.iter() {
|
||||||
filter = filter.exclude(glob.clone());
|
filter = filter.exclude(glob.clone());
|
||||||
|
@ -148,17 +150,9 @@ impl WorldState {
|
||||||
vfs_file.map(|f| FileId(f.0))
|
vfs_file.map(|f| FileId(f.0))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut outdirs = FxHashMap::default();
|
|
||||||
for (name, path) in additional_out_dirs {
|
|
||||||
let path = PathBuf::from(&path);
|
|
||||||
if let Some(id) = extern_source_roots.get(&path) {
|
|
||||||
outdirs.insert(name, (id.clone(), path.to_string_lossy().replace("\\", "/")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
workspaces
|
workspaces
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ws| ws.to_crate_graph(&default_cfg_options, &outdirs, &mut load))
|
.map(|ws| ws.to_crate_graph(&default_cfg_options, &extern_source_roots, &mut load))
|
||||||
.for_each(|graph| {
|
.for_each(|graph| {
|
||||||
crate_graph.extend(graph);
|
crate_graph.extend(graph);
|
||||||
});
|
});
|
||||||
|
|
|
@ -237,11 +237,6 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Whether to ask for permission before downloading any files from the Internet"
|
"description": "Whether to ask for permission before downloading any files from the Internet"
|
||||||
},
|
},
|
||||||
"rust-analyzer.additionalOutDirs": {
|
|
||||||
"type": "object",
|
|
||||||
"default": {},
|
|
||||||
"markdownDescription": "Fine grained controls for OUT_DIR `env!(\"OUT_DIR\")` variable. e.g. `{\"foo\":\"/path/to/foo\"}`, "
|
|
||||||
},
|
|
||||||
"rust-analyzer.serverPath": {
|
"rust-analyzer.serverPath": {
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
@ -362,6 +357,11 @@
|
||||||
},
|
},
|
||||||
"default": [],
|
"default": [],
|
||||||
"description": "List of features to activate"
|
"description": "List of features to activate"
|
||||||
|
},
|
||||||
|
"rust-analyzer.cargoFeatures.loadOutDirsFromCheck": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"markdownDescription": "Run `cargo check` on startup to get the correct value for package OUT_DIRs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,7 +42,6 @@ export async function createClient(config: Config, serverPath: string): Promise<
|
||||||
excludeGlobs: config.excludeGlobs,
|
excludeGlobs: config.excludeGlobs,
|
||||||
useClientWatching: config.useClientWatching,
|
useClientWatching: config.useClientWatching,
|
||||||
featureFlags: config.featureFlags,
|
featureFlags: config.featureFlags,
|
||||||
additionalOutDirs: config.additionalOutDirs,
|
|
||||||
withSysroot: config.withSysroot,
|
withSysroot: config.withSysroot,
|
||||||
cargoFeatures: config.cargoFeatures,
|
cargoFeatures: config.cargoFeatures,
|
||||||
rustfmtArgs: config.rustfmtArgs,
|
rustfmtArgs: config.rustfmtArgs,
|
||||||
|
|
|
@ -22,6 +22,7 @@ export interface CargoFeatures {
|
||||||
noDefaultFeatures: boolean;
|
noDefaultFeatures: boolean;
|
||||||
allFeatures: boolean;
|
allFeatures: boolean;
|
||||||
features: string[];
|
features: string[];
|
||||||
|
loadOutDirsFromCheck: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum UpdatesChannel {
|
export const enum UpdatesChannel {
|
||||||
|
@ -202,8 +203,8 @@ export class Config {
|
||||||
get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; }
|
get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; }
|
||||||
get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; }
|
get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; }
|
||||||
get featureFlags() { return this.cfg.get("featureFlags") as Record<string, boolean>; }
|
get featureFlags() { return this.cfg.get("featureFlags") as Record<string, boolean>; }
|
||||||
get additionalOutDirs() { return this.cfg.get("additionalOutDirs") as Record<string, string>; }
|
|
||||||
get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; }
|
get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; }
|
||||||
|
get loadOutDirsFromCheck() { return this.cfg.get("loadOutDirsFromCheck") as boolean; }
|
||||||
|
|
||||||
get cargoWatchOptions(): CargoWatchOptions {
|
get cargoWatchOptions(): CargoWatchOptions {
|
||||||
return {
|
return {
|
||||||
|
@ -219,6 +220,7 @@ export class Config {
|
||||||
noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean,
|
noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean,
|
||||||
allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean,
|
allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean,
|
||||||
features: this.cfg.get("cargoFeatures.features") as string[],
|
features: this.cfg.get("cargoFeatures.features") as string[],
|
||||||
|
loadOutDirsFromCheck: this.cfg.get("cargoFeatures.loadOutDirsFromCheck") as boolean,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue