aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_project_model
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_project_model')
-rw-r--r--crates/ra_project_model/src/lib.rs87
-rw-r--r--crates/ra_project_model/src/project_json.rs43
2 files changed, 64 insertions, 66 deletions
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 6ca53c6d8..8053712ff 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -7,7 +7,6 @@ mod sysroot;
7use std::{ 7use std::{
8 fs::{self, read_dir, ReadDir}, 8 fs::{self, read_dir, ReadDir},
9 io, 9 io,
10 path::Path,
11 process::{Command, Output}, 10 process::{Command, Output},
12}; 11};
13 12
@@ -36,30 +35,12 @@ pub enum ProjectWorkspace {
36/// `PackageRoot` describes a package root folder. 35/// `PackageRoot` describes a package root folder.
37/// Which may be an external dependency, or a member of 36/// Which may be an external dependency, or a member of
38/// the current workspace. 37/// the current workspace.
39#[derive(Debug, Clone)] 38#[derive(Debug, Clone, Eq, PartialEq, Hash)]
40pub struct PackageRoot { 39pub struct PackageRoot {
41 /// Path to the root folder
42 path: AbsPathBuf,
43 /// Is a member of the current workspace 40 /// Is a member of the current workspace
44 is_member: bool, 41 pub is_member: bool,
45 out_dir: Option<AbsPathBuf>, 42 pub include: Vec<AbsPathBuf>,
46} 43 pub exclude: Vec<AbsPathBuf>,
47impl PackageRoot {
48 pub fn new_member(path: AbsPathBuf) -> PackageRoot {
49 Self { path, is_member: true, out_dir: None }
50 }
51 pub fn new_non_member(path: AbsPathBuf) -> PackageRoot {
52 Self { path, is_member: false, out_dir: None }
53 }
54 pub fn path(&self) -> &AbsPath {
55 &self.path
56 }
57 pub fn out_dir(&self) -> Option<&AbsPath> {
58 self.out_dir.as_deref()
59 }
60 pub fn is_member(&self) -> bool {
61 self.is_member
62 }
63} 44}
64 45
65#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] 46#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
@@ -196,18 +177,40 @@ impl ProjectWorkspace {
196 /// the root is a member of the current workspace 177 /// the root is a member of the current workspace
197 pub fn to_roots(&self) -> Vec<PackageRoot> { 178 pub fn to_roots(&self) -> Vec<PackageRoot> {
198 match self { 179 match self {
199 ProjectWorkspace::Json { project } => { 180 ProjectWorkspace::Json { project } => project
200 project.roots.iter().map(|r| PackageRoot::new_member(r.path.clone())).collect() 181 .crates
201 } 182 .iter()
183 .map(|krate| PackageRoot {
184 is_member: krate.is_workspace_member,
185 include: krate.include.clone(),
186 exclude: krate.exclude.clone(),
187 })
188 .collect::<FxHashSet<_>>()
189 .into_iter()
190 .collect::<Vec<_>>(),
202 ProjectWorkspace::Cargo { cargo, sysroot } => cargo 191 ProjectWorkspace::Cargo { cargo, sysroot } => cargo
203 .packages() 192 .packages()
204 .map(|pkg| PackageRoot { 193 .map(|pkg| {
205 path: cargo[pkg].root().to_path_buf(), 194 let is_member = cargo[pkg].is_member;
206 is_member: cargo[pkg].is_member, 195 let pkg_root = cargo[pkg].root().to_path_buf();
207 out_dir: cargo[pkg].out_dir.clone(), 196
197 let mut include = vec![pkg_root.clone()];
198 include.extend(cargo[pkg].out_dir.clone());
199
200 let mut exclude = vec![pkg_root.join(".git")];
201 if is_member {
202 exclude.push(pkg_root.join("target"));
203 } else {
204 exclude.push(pkg_root.join("tests"));
205 exclude.push(pkg_root.join("examples"));
206 exclude.push(pkg_root.join("benches"));
207 }
208 PackageRoot { is_member, include, exclude }
208 }) 209 })
209 .chain(sysroot.crates().map(|krate| { 210 .chain(sysroot.crates().map(|krate| PackageRoot {
210 PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) 211 is_member: false,
212 include: vec![sysroot[krate].root_dir().to_path_buf()],
213 exclude: Vec::new(),
211 })) 214 }))
212 .collect(), 215 .collect(),
213 } 216 }
@@ -256,13 +259,7 @@ impl ProjectWorkspace {
256 let file_path = &krate.root_module; 259 let file_path = &krate.root_module;
257 let file_id = load(&file_path)?; 260 let file_id = load(&file_path)?;
258 261
259 let mut env = Env::default(); 262 let env = krate.env.clone().into_iter().collect();
260 if let Some(out_dir) = &krate.out_dir {
261 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
262 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
263 env.set("OUT_DIR", out_dir);
264 }
265 }
266 let proc_macro = krate 263 let proc_macro = krate
267 .proc_macro_dylib_path 264 .proc_macro_dylib_path
268 .clone() 265 .clone()
@@ -504,18 +501,6 @@ impl ProjectWorkspace {
504 } 501 }
505 crate_graph 502 crate_graph
506 } 503 }
507
508 pub fn workspace_root_for(&self, path: &Path) -> Option<&AbsPath> {
509 match self {
510 ProjectWorkspace::Cargo { cargo, .. } => {
511 Some(cargo.workspace_root()).filter(|root| path.starts_with(root))
512 }
513 ProjectWorkspace::Json { project: ProjectJson { roots, .. }, .. } => roots
514 .iter()
515 .find(|root| path.starts_with(&root.path))
516 .map(|root| root.path.as_path()),
517 }
518 }
519} 504}
520 505
521fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { 506fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions {
diff --git a/crates/ra_project_model/src/project_json.rs b/crates/ra_project_model/src/project_json.rs
index 778cc84ef..e9a333191 100644
--- a/crates/ra_project_model/src/project_json.rs
+++ b/crates/ra_project_model/src/project_json.rs
@@ -5,24 +5,16 @@ use std::path::PathBuf;
5use paths::{AbsPath, AbsPathBuf}; 5use paths::{AbsPath, AbsPathBuf};
6use ra_cfg::CfgOptions; 6use ra_cfg::CfgOptions;
7use ra_db::{CrateId, CrateName, Dependency, Edition}; 7use ra_db::{CrateId, CrateName, Dependency, Edition};
8use rustc_hash::FxHashSet; 8use rustc_hash::{FxHashMap, FxHashSet};
9use serde::{de, Deserialize}; 9use serde::{de, Deserialize};
10use stdx::split_delim; 10use stdx::split_delim;
11 11
12/// Roots and crates that compose this Rust project. 12/// Roots and crates that compose this Rust project.
13#[derive(Clone, Debug, Eq, PartialEq)] 13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ProjectJson { 14pub struct ProjectJson {
15 pub(crate) roots: Vec<Root>,
16 pub(crate) crates: Vec<Crate>, 15 pub(crate) crates: Vec<Crate>,
17} 16}
18 17
19/// A root points to the directory which contains Rust crates. rust-analyzer watches all files in
20/// all roots. Roots might be nested.
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct Root {
23 pub(crate) path: AbsPathBuf,
24}
25
26/// A crate points to the root module of a crate and lists the dependencies of the crate. This is 18/// A crate points to the root module of a crate and lists the dependencies of the crate. This is
27/// useful in creating the crate graph. 19/// useful in creating the crate graph.
28#[derive(Clone, Debug, Eq, PartialEq)] 20#[derive(Clone, Debug, Eq, PartialEq)]
@@ -32,15 +24,16 @@ pub struct Crate {
32 pub(crate) deps: Vec<Dependency>, 24 pub(crate) deps: Vec<Dependency>,
33 pub(crate) cfg: CfgOptions, 25 pub(crate) cfg: CfgOptions,
34 pub(crate) target: Option<String>, 26 pub(crate) target: Option<String>,
35 pub(crate) out_dir: Option<AbsPathBuf>, 27 pub(crate) env: FxHashMap<String, String>,
36 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, 28 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
37 pub(crate) is_workspace_member: bool, 29 pub(crate) is_workspace_member: bool,
30 pub(crate) include: Vec<AbsPathBuf>,
31 pub(crate) exclude: Vec<AbsPathBuf>,
38} 32}
39 33
40impl ProjectJson { 34impl ProjectJson {
41 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { 35 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
42 ProjectJson { 36 ProjectJson {
43 roots: data.roots.into_iter().map(|path| Root { path: base.join(path) }).collect(),
44 crates: data 37 crates: data
45 .crates 38 .crates
46 .into_iter() 39 .into_iter()
@@ -50,8 +43,19 @@ impl ProjectJson {
50 && !crate_data.root_module.starts_with("..") 43 && !crate_data.root_module.starts_with("..")
51 || crate_data.root_module.starts_with(base) 44 || crate_data.root_module.starts_with(base)
52 }); 45 });
46 let root_module = base.join(crate_data.root_module);
47 let (include, exclude) = match crate_data.source {
48 Some(src) => {
49 let absolutize = |dirs: Vec<PathBuf>| {
50 dirs.into_iter().map(|it| base.join(it)).collect::<Vec<_>>()
51 };
52 (absolutize(src.include_dirs), absolutize(src.exclude_dirs))
53 }
54 None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
55 };
56
53 Crate { 57 Crate {
54 root_module: base.join(crate_data.root_module), 58 root_module,
55 edition: crate_data.edition.into(), 59 edition: crate_data.edition.into(),
56 deps: crate_data 60 deps: crate_data
57 .deps 61 .deps
@@ -74,11 +78,13 @@ impl ProjectJson {
74 cfg 78 cfg
75 }, 79 },
76 target: crate_data.target, 80 target: crate_data.target,
77 out_dir: crate_data.out_dir.map(|it| base.join(it)), 81 env: crate_data.env,
78 proc_macro_dylib_path: crate_data 82 proc_macro_dylib_path: crate_data
79 .proc_macro_dylib_path 83 .proc_macro_dylib_path
80 .map(|it| base.join(it)), 84 .map(|it| base.join(it)),
81 is_workspace_member, 85 is_workspace_member,
86 include,
87 exclude,
82 } 88 }
83 }) 89 })
84 .collect::<Vec<_>>(), 90 .collect::<Vec<_>>(),
@@ -88,7 +94,6 @@ impl ProjectJson {
88 94
89#[derive(Deserialize)] 95#[derive(Deserialize)]
90pub struct ProjectJsonData { 96pub struct ProjectJsonData {
91 roots: Vec<PathBuf>,
92 crates: Vec<CrateData>, 97 crates: Vec<CrateData>,
93} 98}
94 99
@@ -100,9 +105,11 @@ struct CrateData {
100 #[serde(default)] 105 #[serde(default)]
101 cfg: FxHashSet<String>, 106 cfg: FxHashSet<String>,
102 target: Option<String>, 107 target: Option<String>,
103 out_dir: Option<PathBuf>, 108 #[serde(default)]
109 env: FxHashMap<String, String>,
104 proc_macro_dylib_path: Option<PathBuf>, 110 proc_macro_dylib_path: Option<PathBuf>,
105 is_workspace_member: Option<bool>, 111 is_workspace_member: Option<bool>,
112 source: Option<CrateSource>,
106} 113}
107 114
108#[derive(Deserialize)] 115#[derive(Deserialize)]
@@ -132,6 +139,12 @@ struct DepData {
132 name: CrateName, 139 name: CrateName,
133} 140}
134 141
142#[derive(Deserialize)]
143struct CrateSource {
144 include_dirs: Vec<PathBuf>,
145 exclude_dirs: Vec<PathBuf>,
146}
147
135fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error> 148fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
136where 149where
137 D: de::Deserializer<'de>, 150 D: de::Deserializer<'de>,