diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/paths/src/lib.rs | 26 | ||||
-rw-r--r-- | crates/ra_project_model/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 42 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 51 | ||||
-rw-r--r-- | crates/ra_project_model/src/sysroot.rs | 23 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 37 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 7 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/support.rs | 8 |
10 files changed, 125 insertions, 94 deletions
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index 45b19c45a..1b259682d 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs | |||
@@ -28,6 +28,12 @@ impl AsRef<Path> for AbsPathBuf { | |||
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | impl AsRef<AbsPath> for AbsPathBuf { | ||
32 | fn as_ref(&self) -> &AbsPath { | ||
33 | self.as_path() | ||
34 | } | ||
35 | } | ||
36 | |||
31 | impl TryFrom<PathBuf> for AbsPathBuf { | 37 | impl TryFrom<PathBuf> for AbsPathBuf { |
32 | type Error = PathBuf; | 38 | type Error = PathBuf; |
33 | fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { | 39 | fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { |
@@ -45,9 +51,19 @@ impl TryFrom<&str> for AbsPathBuf { | |||
45 | } | 51 | } |
46 | } | 52 | } |
47 | 53 | ||
54 | impl PartialEq<AbsPath> for AbsPathBuf { | ||
55 | fn eq(&self, other: &AbsPath) -> bool { | ||
56 | self.as_path() == other | ||
57 | } | ||
58 | } | ||
59 | |||
48 | impl AbsPathBuf { | 60 | impl AbsPathBuf { |
61 | pub fn assert(path: PathBuf) -> AbsPathBuf { | ||
62 | AbsPathBuf::try_from(path) | ||
63 | .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display())) | ||
64 | } | ||
49 | pub fn as_path(&self) -> &AbsPath { | 65 | pub fn as_path(&self) -> &AbsPath { |
50 | AbsPath::new_unchecked(self.0.as_path()) | 66 | AbsPath::assert(self.0.as_path()) |
51 | } | 67 | } |
52 | pub fn pop(&mut self) -> bool { | 68 | pub fn pop(&mut self) -> bool { |
53 | self.0.pop() | 69 | self.0.pop() |
@@ -77,15 +93,19 @@ impl<'a> TryFrom<&'a Path> for &'a AbsPath { | |||
77 | if !path.is_absolute() { | 93 | if !path.is_absolute() { |
78 | return Err(path); | 94 | return Err(path); |
79 | } | 95 | } |
80 | Ok(AbsPath::new_unchecked(path)) | 96 | Ok(AbsPath::assert(path)) |
81 | } | 97 | } |
82 | } | 98 | } |
83 | 99 | ||
84 | impl AbsPath { | 100 | impl AbsPath { |
85 | fn new_unchecked(path: &Path) -> &AbsPath { | 101 | pub fn assert(path: &Path) -> &AbsPath { |
102 | assert!(path.is_absolute()); | ||
86 | unsafe { &*(path as *const Path as *const AbsPath) } | 103 | unsafe { &*(path as *const Path as *const AbsPath) } |
87 | } | 104 | } |
88 | 105 | ||
106 | pub fn parent(&self) -> Option<&AbsPath> { | ||
107 | self.0.parent().map(AbsPath::assert) | ||
108 | } | ||
89 | pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { | 109 | pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { |
90 | self.as_ref().join(path).try_into().unwrap() | 110 | self.as_ref().join(path).try_into().unwrap() |
91 | } | 111 | } |
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index e4a60f4c0..818947014 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -18,6 +18,7 @@ ra_cfg = { path = "../ra_cfg" } | |||
18 | ra_db = { path = "../ra_db" } | 18 | ra_db = { path = "../ra_db" } |
19 | ra_toolchain = { path = "../ra_toolchain" } | 19 | ra_toolchain = { path = "../ra_toolchain" } |
20 | ra_proc_macro = { path = "../ra_proc_macro" } | 20 | ra_proc_macro = { path = "../ra_proc_macro" } |
21 | paths = { path = "../paths" } | ||
21 | 22 | ||
22 | serde = { version = "1.0.106", features = ["derive"] } | 23 | serde = { version = "1.0.106", features = ["derive"] } |
23 | serde_json = "1.0.48" | 24 | serde_json = "1.0.48" |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 4b7444039..8ce63ab3c 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -1,14 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ffi::OsStr, ops, path::Path, process::Command}; |
4 | ffi::OsStr, | ||
5 | ops, | ||
6 | path::{Path, PathBuf}, | ||
7 | process::Command, | ||
8 | }; | ||
9 | 4 | ||
10 | use anyhow::{Context, Result}; | 5 | use anyhow::{Context, Result}; |
11 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; | 6 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; |
7 | use paths::{AbsPath, AbsPathBuf}; | ||
12 | use ra_arena::{Arena, Idx}; | 8 | use ra_arena::{Arena, Idx}; |
13 | use ra_db::Edition; | 9 | use ra_db::Edition; |
14 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
@@ -20,11 +16,14 @@ use rustc_hash::FxHashMap; | |||
20 | /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, | 16 | /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, |
21 | /// while this knows about `Packages` & `Targets`: purely cargo-related | 17 | /// while this knows about `Packages` & `Targets`: purely cargo-related |
22 | /// concepts. | 18 | /// concepts. |
19 | /// | ||
20 | /// We use absolute paths here, `cargo metadata` guarantees to always produce | ||
21 | /// abs paths. | ||
23 | #[derive(Debug, Clone)] | 22 | #[derive(Debug, Clone)] |
24 | pub struct CargoWorkspace { | 23 | pub struct CargoWorkspace { |
25 | packages: Arena<PackageData>, | 24 | packages: Arena<PackageData>, |
26 | targets: Arena<TargetData>, | 25 | targets: Arena<TargetData>, |
27 | workspace_root: PathBuf, | 26 | workspace_root: AbsPathBuf, |
28 | } | 27 | } |
29 | 28 | ||
30 | impl ops::Index<Package> for CargoWorkspace { | 29 | impl ops::Index<Package> for CargoWorkspace { |
@@ -80,15 +79,15 @@ pub type Target = Idx<TargetData>; | |||
80 | pub struct PackageData { | 79 | pub struct PackageData { |
81 | pub version: String, | 80 | pub version: String, |
82 | pub name: String, | 81 | pub name: String, |
83 | pub manifest: PathBuf, | 82 | pub manifest: AbsPathBuf, |
84 | pub targets: Vec<Target>, | 83 | pub targets: Vec<Target>, |
85 | pub is_member: bool, | 84 | pub is_member: bool, |
86 | pub dependencies: Vec<PackageDependency>, | 85 | pub dependencies: Vec<PackageDependency>, |
87 | pub edition: Edition, | 86 | pub edition: Edition, |
88 | pub features: Vec<String>, | 87 | pub features: Vec<String>, |
89 | pub cfgs: Vec<String>, | 88 | pub cfgs: Vec<String>, |
90 | pub out_dir: Option<PathBuf>, | 89 | pub out_dir: Option<AbsPathBuf>, |
91 | pub proc_macro_dylib_path: Option<PathBuf>, | 90 | pub proc_macro_dylib_path: Option<AbsPathBuf>, |
92 | } | 91 | } |
93 | 92 | ||
94 | #[derive(Debug, Clone)] | 93 | #[derive(Debug, Clone)] |
@@ -101,7 +100,7 @@ pub struct PackageDependency { | |||
101 | pub struct TargetData { | 100 | pub struct TargetData { |
102 | pub package: Package, | 101 | pub package: Package, |
103 | pub name: String, | 102 | pub name: String, |
104 | pub root: PathBuf, | 103 | pub root: AbsPathBuf, |
105 | pub kind: TargetKind, | 104 | pub kind: TargetKind, |
106 | pub is_proc_macro: bool, | 105 | pub is_proc_macro: bool, |
107 | } | 106 | } |
@@ -135,7 +134,7 @@ impl TargetKind { | |||
135 | } | 134 | } |
136 | 135 | ||
137 | impl PackageData { | 136 | impl PackageData { |
138 | pub fn root(&self) -> &Path { | 137 | pub fn root(&self) -> &AbsPath { |
139 | self.manifest.parent().unwrap() | 138 | self.manifest.parent().unwrap() |
140 | } | 139 | } |
141 | } | 140 | } |
@@ -193,7 +192,7 @@ impl CargoWorkspace { | |||
193 | let pkg = packages.alloc(PackageData { | 192 | let pkg = packages.alloc(PackageData { |
194 | name, | 193 | name, |
195 | version: version.to_string(), | 194 | version: version.to_string(), |
196 | manifest: manifest_path, | 195 | manifest: AbsPathBuf::assert(manifest_path), |
197 | targets: Vec::new(), | 196 | targets: Vec::new(), |
198 | is_member, | 197 | is_member, |
199 | edition, | 198 | edition, |
@@ -210,7 +209,7 @@ impl CargoWorkspace { | |||
210 | let tgt = targets.alloc(TargetData { | 209 | let tgt = targets.alloc(TargetData { |
211 | package: pkg, | 210 | package: pkg, |
212 | name: meta_tgt.name, | 211 | name: meta_tgt.name, |
213 | root: meta_tgt.src_path.clone(), | 212 | root: AbsPathBuf::assert(meta_tgt.src_path.clone()), |
214 | kind: TargetKind::new(meta_tgt.kind.as_slice()), | 213 | kind: TargetKind::new(meta_tgt.kind.as_slice()), |
215 | is_proc_macro, | 214 | is_proc_macro, |
216 | }); | 215 | }); |
@@ -246,16 +245,17 @@ impl CargoWorkspace { | |||
246 | packages[source].features.extend(node.features); | 245 | packages[source].features.extend(node.features); |
247 | } | 246 | } |
248 | 247 | ||
249 | Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root }) | 248 | let workspace_root = AbsPathBuf::assert(meta.workspace_root); |
249 | Ok(CargoWorkspace { packages, targets, workspace_root: workspace_root }) | ||
250 | } | 250 | } |
251 | 251 | ||
252 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a { | 252 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a { |
253 | self.packages.iter().map(|(id, _pkg)| id) | 253 | self.packages.iter().map(|(id, _pkg)| id) |
254 | } | 254 | } |
255 | 255 | ||
256 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { | 256 | pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> { |
257 | self.packages() | 257 | self.packages() |
258 | .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root)) | 258 | .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root)) |
259 | .next() | 259 | .next() |
260 | .copied() | 260 | .copied() |
261 | } | 261 | } |
@@ -279,8 +279,8 @@ impl CargoWorkspace { | |||
279 | 279 | ||
280 | #[derive(Debug, Clone, Default)] | 280 | #[derive(Debug, Clone, Default)] |
281 | pub struct ExternResources { | 281 | pub struct ExternResources { |
282 | out_dirs: FxHashMap<PackageId, PathBuf>, | 282 | out_dirs: FxHashMap<PackageId, AbsPathBuf>, |
283 | proc_dylib_paths: FxHashMap<PackageId, PathBuf>, | 283 | proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>, |
284 | cfgs: FxHashMap<PackageId, Vec<String>>, | 284 | cfgs: FxHashMap<PackageId, Vec<String>>, |
285 | } | 285 | } |
286 | 286 | ||
@@ -308,6 +308,7 @@ pub fn load_extern_resources( | |||
308 | if let Ok(message) = message { | 308 | if let Ok(message) = message { |
309 | match message { | 309 | match message { |
310 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { | 310 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { |
311 | let out_dir = AbsPathBuf::assert(out_dir); | ||
311 | res.out_dirs.insert(package_id.clone(), out_dir); | 312 | res.out_dirs.insert(package_id.clone(), out_dir); |
312 | res.cfgs.insert(package_id, cfgs); | 313 | res.cfgs.insert(package_id, cfgs); |
313 | } | 314 | } |
@@ -317,7 +318,8 @@ pub fn load_extern_resources( | |||
317 | // Skip rmeta file | 318 | // Skip rmeta file |
318 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) | 319 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) |
319 | { | 320 | { |
320 | res.proc_dylib_paths.insert(package_id, filename.clone()); | 321 | let filename = AbsPathBuf::assert(filename.clone()); |
322 | res.proc_dylib_paths.insert(package_id, filename); | ||
321 | } | 323 | } |
322 | } | 324 | } |
323 | } | 325 | } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fe3e81689..ac88532f0 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -7,11 +7,12 @@ mod sysroot; | |||
7 | use std::{ | 7 | use std::{ |
8 | fs::{read_dir, File, ReadDir}, | 8 | fs::{read_dir, File, ReadDir}, |
9 | io::{self, BufReader}, | 9 | io::{self, BufReader}, |
10 | path::{Path, PathBuf}, | 10 | path::Path, |
11 | process::{Command, Output}, | 11 | process::{Command, Output}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use anyhow::{bail, Context, Result}; | 14 | use anyhow::{bail, Context, Result}; |
15 | use paths::{AbsPath, AbsPathBuf}; | ||
15 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
16 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; | 17 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; |
17 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -29,7 +30,7 @@ pub enum ProjectWorkspace { | |||
29 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 30 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
30 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, | 31 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, |
31 | /// Project workspace was manually specified using a `rust-project.json` file. | 32 | /// Project workspace was manually specified using a `rust-project.json` file. |
32 | Json { project: JsonProject, project_location: PathBuf }, | 33 | Json { project: JsonProject, project_location: AbsPathBuf }, |
33 | } | 34 | } |
34 | 35 | ||
35 | /// `PackageRoot` describes a package root folder. | 36 | /// `PackageRoot` describes a package root folder. |
@@ -38,22 +39,22 @@ pub enum ProjectWorkspace { | |||
38 | #[derive(Debug, Clone)] | 39 | #[derive(Debug, Clone)] |
39 | pub struct PackageRoot { | 40 | pub struct PackageRoot { |
40 | /// Path to the root folder | 41 | /// Path to the root folder |
41 | path: PathBuf, | 42 | path: AbsPathBuf, |
42 | /// Is a member of the current workspace | 43 | /// Is a member of the current workspace |
43 | is_member: bool, | 44 | is_member: bool, |
44 | out_dir: Option<PathBuf>, | 45 | out_dir: Option<AbsPathBuf>, |
45 | } | 46 | } |
46 | impl PackageRoot { | 47 | impl PackageRoot { |
47 | pub fn new_member(path: PathBuf) -> PackageRoot { | 48 | pub fn new_member(path: AbsPathBuf) -> PackageRoot { |
48 | Self { path, is_member: true, out_dir: None } | 49 | Self { path, is_member: true, out_dir: None } |
49 | } | 50 | } |
50 | pub fn new_non_member(path: PathBuf) -> PackageRoot { | 51 | pub fn new_non_member(path: AbsPathBuf) -> PackageRoot { |
51 | Self { path, is_member: false, out_dir: None } | 52 | Self { path, is_member: false, out_dir: None } |
52 | } | 53 | } |
53 | pub fn path(&self) -> &Path { | 54 | pub fn path(&self) -> &AbsPath { |
54 | &self.path | 55 | &self.path |
55 | } | 56 | } |
56 | pub fn out_dir(&self) -> Option<&Path> { | 57 | pub fn out_dir(&self) -> Option<&AbsPath> { |
57 | self.out_dir.as_deref() | 58 | self.out_dir.as_deref() |
58 | } | 59 | } |
59 | pub fn is_member(&self) -> bool { | 60 | pub fn is_member(&self) -> bool { |
@@ -63,12 +64,12 @@ impl PackageRoot { | |||
63 | 64 | ||
64 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | 65 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] |
65 | pub enum ProjectManifest { | 66 | pub enum ProjectManifest { |
66 | ProjectJson(PathBuf), | 67 | ProjectJson(AbsPathBuf), |
67 | CargoToml(PathBuf), | 68 | CargoToml(AbsPathBuf), |
68 | } | 69 | } |
69 | 70 | ||
70 | impl ProjectManifest { | 71 | impl ProjectManifest { |
71 | pub fn from_manifest_file(path: PathBuf) -> Result<ProjectManifest> { | 72 | pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> { |
72 | if path.ends_with("rust-project.json") { | 73 | if path.ends_with("rust-project.json") { |
73 | return Ok(ProjectManifest::ProjectJson(path)); | 74 | return Ok(ProjectManifest::ProjectJson(path)); |
74 | } | 75 | } |
@@ -78,7 +79,7 @@ impl ProjectManifest { | |||
78 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) | 79 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) |
79 | } | 80 | } |
80 | 81 | ||
81 | pub fn discover_single(path: &Path) -> Result<ProjectManifest> { | 82 | pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> { |
82 | let mut candidates = ProjectManifest::discover(path)?; | 83 | let mut candidates = ProjectManifest::discover(path)?; |
83 | let res = match candidates.pop() { | 84 | let res = match candidates.pop() { |
84 | None => bail!("no projects"), | 85 | None => bail!("no projects"), |
@@ -91,23 +92,23 @@ impl ProjectManifest { | |||
91 | Ok(res) | 92 | Ok(res) |
92 | } | 93 | } |
93 | 94 | ||
94 | pub fn discover(path: &Path) -> io::Result<Vec<ProjectManifest>> { | 95 | pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> { |
95 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { | 96 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { |
96 | return Ok(vec![ProjectManifest::ProjectJson(project_json)]); | 97 | return Ok(vec![ProjectManifest::ProjectJson(project_json)]); |
97 | } | 98 | } |
98 | return find_cargo_toml(path) | 99 | return find_cargo_toml(path) |
99 | .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); | 100 | .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); |
100 | 101 | ||
101 | fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> { | 102 | fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> { |
102 | match find_in_parent_dirs(path, "Cargo.toml") { | 103 | match find_in_parent_dirs(path, "Cargo.toml") { |
103 | Some(it) => Ok(vec![it]), | 104 | Some(it) => Ok(vec![it]), |
104 | None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), | 105 | None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), |
105 | } | 106 | } |
106 | } | 107 | } |
107 | 108 | ||
108 | fn find_in_parent_dirs(path: &Path, target_file_name: &str) -> Option<PathBuf> { | 109 | fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> { |
109 | if path.ends_with(target_file_name) { | 110 | if path.ends_with(target_file_name) { |
110 | return Some(path.to_owned()); | 111 | return Some(path.to_path_buf()); |
111 | } | 112 | } |
112 | 113 | ||
113 | let mut curr = Some(path); | 114 | let mut curr = Some(path); |
@@ -123,17 +124,18 @@ impl ProjectManifest { | |||
123 | None | 124 | None |
124 | } | 125 | } |
125 | 126 | ||
126 | fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> { | 127 | fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> { |
127 | // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects | 128 | // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects |
128 | entities | 129 | entities |
129 | .filter_map(Result::ok) | 130 | .filter_map(Result::ok) |
130 | .map(|it| it.path().join("Cargo.toml")) | 131 | .map(|it| it.path().join("Cargo.toml")) |
131 | .filter(|it| it.exists()) | 132 | .filter(|it| it.exists()) |
133 | .map(AbsPathBuf::assert) | ||
132 | .collect() | 134 | .collect() |
133 | } | 135 | } |
134 | } | 136 | } |
135 | 137 | ||
136 | pub fn discover_all(paths: &[impl AsRef<Path>]) -> Vec<ProjectManifest> { | 138 | pub fn discover_all(paths: &[impl AsRef<AbsPath>]) -> Vec<ProjectManifest> { |
137 | let mut res = paths | 139 | let mut res = paths |
138 | .iter() | 140 | .iter() |
139 | .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) | 141 | .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) |
@@ -158,15 +160,12 @@ impl ProjectWorkspace { | |||
158 | format!("Failed to open json file {}", project_json.display()) | 160 | format!("Failed to open json file {}", project_json.display()) |
159 | })?; | 161 | })?; |
160 | let reader = BufReader::new(file); | 162 | let reader = BufReader::new(file); |
161 | let project_location = match project_json.parent() { | 163 | let project_location = project_json.parent().unwrap().to_path_buf(); |
162 | Some(parent) => PathBuf::from(parent), | ||
163 | None => PathBuf::new(), | ||
164 | }; | ||
165 | ProjectWorkspace::Json { | 164 | ProjectWorkspace::Json { |
166 | project: from_reader(reader).with_context(|| { | 165 | project: from_reader(reader).with_context(|| { |
167 | format!("Failed to deserialize json file {}", project_json.display()) | 166 | format!("Failed to deserialize json file {}", project_json.display()) |
168 | })?, | 167 | })?, |
169 | project_location: project_location, | 168 | project_location, |
170 | } | 169 | } |
171 | } | 170 | } |
172 | ProjectManifest::CargoToml(cargo_toml) => { | 171 | ProjectManifest::CargoToml(cargo_toml) => { |
@@ -218,13 +217,13 @@ impl ProjectWorkspace { | |||
218 | } | 217 | } |
219 | } | 218 | } |
220 | 219 | ||
221 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { | 220 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { |
222 | match self { | 221 | match self { |
223 | ProjectWorkspace::Json { project, .. } => project | 222 | ProjectWorkspace::Json { project, project_location } => project |
224 | .crates | 223 | .crates |
225 | .iter() | 224 | .iter() |
226 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) | 225 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) |
227 | .cloned() | 226 | .map(|it| project_location.join(it)) |
228 | .collect(), | 227 | .collect(), |
229 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo | 228 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo |
230 | .packages() | 229 | .packages() |
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index a8a196e64..943ff92df 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs | |||
@@ -1,15 +1,12 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{convert::TryFrom, env, ops, path::Path, process::Command}; |
4 | env, ops, | ||
5 | path::{Path, PathBuf}, | ||
6 | process::Command, | ||
7 | }; | ||
8 | 4 | ||
9 | use anyhow::{bail, Result}; | 5 | use anyhow::{bail, format_err, Result}; |
10 | use ra_arena::{Arena, Idx}; | 6 | use ra_arena::{Arena, Idx}; |
11 | 7 | ||
12 | use crate::output; | 8 | use crate::output; |
9 | use paths::{AbsPath, AbsPathBuf}; | ||
13 | 10 | ||
14 | #[derive(Default, Debug, Clone)] | 11 | #[derive(Default, Debug, Clone)] |
15 | pub struct Sysroot { | 12 | pub struct Sysroot { |
@@ -21,7 +18,7 @@ pub type SysrootCrate = Idx<SysrootCrateData>; | |||
21 | #[derive(Debug, Clone)] | 18 | #[derive(Debug, Clone)] |
22 | pub struct SysrootCrateData { | 19 | pub struct SysrootCrateData { |
23 | pub name: String, | 20 | pub name: String, |
24 | pub root: PathBuf, | 21 | pub root: AbsPathBuf, |
25 | pub deps: Vec<SysrootCrate>, | 22 | pub deps: Vec<SysrootCrate>, |
26 | } | 23 | } |
27 | 24 | ||
@@ -53,7 +50,7 @@ impl Sysroot { | |||
53 | self.crates.iter().map(|(id, _data)| id) | 50 | self.crates.iter().map(|(id, _data)| id) |
54 | } | 51 | } |
55 | 52 | ||
56 | pub fn discover(cargo_toml: &Path) -> Result<Sysroot> { | 53 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { |
57 | let src = get_or_install_rust_src(cargo_toml)?; | 54 | let src = get_or_install_rust_src(cargo_toml)?; |
58 | let mut sysroot = Sysroot { crates: Arena::default() }; | 55 | let mut sysroot = Sysroot { crates: Arena::default() }; |
59 | for name in SYSROOT_CRATES.trim().lines() { | 56 | for name in SYSROOT_CRATES.trim().lines() { |
@@ -86,16 +83,18 @@ impl Sysroot { | |||
86 | } | 83 | } |
87 | } | 84 | } |
88 | 85 | ||
89 | fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> { | 86 | fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result<AbsPathBuf> { |
90 | if let Ok(path) = env::var("RUST_SRC_PATH") { | 87 | if let Ok(path) = env::var("RUST_SRC_PATH") { |
91 | return Ok(path.into()); | 88 | let path = AbsPathBuf::try_from(path.as_str()) |
89 | .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?; | ||
90 | return Ok(path); | ||
92 | } | 91 | } |
93 | let current_dir = cargo_toml.parent().unwrap(); | 92 | let current_dir = cargo_toml.parent().unwrap(); |
94 | let mut rustc = Command::new(ra_toolchain::rustc()); | 93 | let mut rustc = Command::new(ra_toolchain::rustc()); |
95 | rustc.current_dir(current_dir).args(&["--print", "sysroot"]); | 94 | rustc.current_dir(current_dir).args(&["--print", "sysroot"]); |
96 | let rustc_output = output(rustc)?; | 95 | let rustc_output = output(rustc)?; |
97 | let stdout = String::from_utf8(rustc_output.stdout)?; | 96 | let stdout = String::from_utf8(rustc_output.stdout)?; |
98 | let sysroot_path = Path::new(stdout.trim()); | 97 | let sysroot_path = AbsPath::assert(Path::new(stdout.trim())); |
99 | let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); | 98 | let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); |
100 | 99 | ||
101 | if !src_path.exists() { | 100 | if !src_path.exists() { |
@@ -116,7 +115,7 @@ fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> { | |||
116 | } | 115 | } |
117 | 116 | ||
118 | impl SysrootCrateData { | 117 | impl SysrootCrateData { |
119 | pub fn root_dir(&self) -> &Path { | 118 | pub fn root_dir(&self) -> &AbsPath { |
120 | self.root.parent().unwrap() | 119 | self.root.parent().unwrap() |
121 | } | 120 | } |
122 | } | 121 | } |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 99e3f7173..45204d1a3 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -3,6 +3,8 @@ | |||
3 | //! Based on cli flags, either spawns an LSP server, or runs a batch analysis | 3 | //! Based on cli flags, either spawns an LSP server, or runs a batch analysis |
4 | mod args; | 4 | mod args; |
5 | 5 | ||
6 | use std::convert::TryFrom; | ||
7 | |||
6 | use lsp_server::Connection; | 8 | use lsp_server::Connection; |
7 | use rust_analyzer::{ | 9 | use rust_analyzer::{ |
8 | cli, | 10 | cli, |
@@ -10,9 +12,11 @@ use rust_analyzer::{ | |||
10 | from_json, Result, | 12 | from_json, Result, |
11 | }; | 13 | }; |
12 | 14 | ||
13 | use crate::args::HelpPrinted; | 15 | use ra_db::AbsPathBuf; |
14 | use ra_project_model::ProjectManifest; | 16 | use ra_project_model::ProjectManifest; |
15 | 17 | ||
18 | use crate::args::HelpPrinted; | ||
19 | |||
16 | fn main() -> Result<()> { | 20 | fn main() -> Result<()> { |
17 | setup_logging()?; | 21 | setup_logging()?; |
18 | let args = match args::Args::parse()? { | 22 | let args = match args::Args::parse()? { |
@@ -20,6 +24,9 @@ fn main() -> Result<()> { | |||
20 | Err(HelpPrinted) => return Ok(()), | 24 | Err(HelpPrinted) => return Ok(()), |
21 | }; | 25 | }; |
22 | match args.command { | 26 | match args.command { |
27 | args::Command::RunServer => run_server()?, | ||
28 | args::Command::ProcMacro => ra_proc_macro_srv::cli::run()?, | ||
29 | |||
23 | args::Command::Parse { no_dump } => cli::parse(no_dump)?, | 30 | args::Command::Parse { no_dump } => cli::parse(no_dump)?, |
24 | args::Command::Symbols => cli::symbols()?, | 31 | args::Command::Symbols => cli::symbols()?, |
25 | args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, | 32 | args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, |
@@ -41,7 +48,6 @@ fn main() -> Result<()> { | |||
41 | load_output_dirs, | 48 | load_output_dirs, |
42 | with_proc_macro, | 49 | with_proc_macro, |
43 | )?, | 50 | )?, |
44 | |||
45 | args::Command::Bench { path, what, load_output_dirs, with_proc_macro } => { | 51 | args::Command::Bench { path, what, load_output_dirs, with_proc_macro } => { |
46 | cli::analysis_bench( | 52 | cli::analysis_bench( |
47 | args.verbosity, | 53 | args.verbosity, |
@@ -51,13 +57,9 @@ fn main() -> Result<()> { | |||
51 | with_proc_macro, | 57 | with_proc_macro, |
52 | )? | 58 | )? |
53 | } | 59 | } |
54 | |||
55 | args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { | 60 | args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { |
56 | cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? | 61 | cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? |
57 | } | 62 | } |
58 | |||
59 | args::Command::ProcMacro => run_proc_macro_srv()?, | ||
60 | args::Command::RunServer => run_server()?, | ||
61 | args::Command::Version => println!("rust-analyzer {}", env!("REV")), | 63 | args::Command::Version => println!("rust-analyzer {}", env!("REV")), |
62 | } | 64 | } |
63 | Ok(()) | 65 | Ok(()) |
@@ -70,11 +72,6 @@ fn setup_logging() -> Result<()> { | |||
70 | Ok(()) | 72 | Ok(()) |
71 | } | 73 | } |
72 | 74 | ||
73 | fn run_proc_macro_srv() -> Result<()> { | ||
74 | ra_proc_macro_srv::cli::run()?; | ||
75 | Ok(()) | ||
76 | } | ||
77 | |||
78 | fn run_server() -> Result<()> { | 75 | fn run_server() -> Result<()> { |
79 | log::info!("lifecycle: server started"); | 76 | log::info!("lifecycle: server started"); |
80 | 77 | ||
@@ -103,14 +100,23 @@ fn run_server() -> Result<()> { | |||
103 | } | 100 | } |
104 | 101 | ||
105 | let config = { | 102 | let config = { |
106 | let mut config = Config::default(); | 103 | let root_path = match initialize_params |
104 | .root_uri | ||
105 | .and_then(|it| it.to_file_path().ok()) | ||
106 | .and_then(|it| AbsPathBuf::try_from(it).ok()) | ||
107 | { | ||
108 | Some(it) => it, | ||
109 | None => { | ||
110 | let cwd = std::env::current_dir()?; | ||
111 | AbsPathBuf::assert(cwd) | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | let mut config = Config::new(root_path); | ||
107 | if let Some(value) = &initialize_params.initialization_options { | 116 | if let Some(value) = &initialize_params.initialization_options { |
108 | config.update(value); | 117 | config.update(value); |
109 | } | 118 | } |
110 | config.update_caps(&initialize_params.capabilities); | 119 | config.update_caps(&initialize_params.capabilities); |
111 | let cwd = std::env::current_dir()?; | ||
112 | config.root_path = | ||
113 | initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); | ||
114 | 120 | ||
115 | if config.linked_projects.is_empty() { | 121 | if config.linked_projects.is_empty() { |
116 | let workspace_roots = initialize_params | 122 | let workspace_roots = initialize_params |
@@ -119,6 +125,7 @@ fn run_server() -> Result<()> { | |||
119 | workspaces | 125 | workspaces |
120 | .into_iter() | 126 | .into_iter() |
121 | .filter_map(|it| it.uri.to_file_path().ok()) | 127 | .filter_map(|it| it.uri.to_file_path().ok()) |
128 | .filter_map(|it| AbsPathBuf::try_from(it).ok()) | ||
122 | .collect::<Vec<_>>() | 129 | .collect::<Vec<_>>() |
123 | }) | 130 | }) |
124 | .filter(|workspaces| !workspaces.is_empty()) | 131 | .filter(|workspaces| !workspaces.is_empty()) |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 00bbbaf40..e910db6eb 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -16,7 +16,7 @@ pub fn load_cargo( | |||
16 | load_out_dirs_from_check: bool, | 16 | load_out_dirs_from_check: bool, |
17 | with_proc_macro: bool, | 17 | with_proc_macro: bool, |
18 | ) -> Result<(AnalysisHost, vfs::Vfs)> { | 18 | ) -> Result<(AnalysisHost, vfs::Vfs)> { |
19 | let root = std::env::current_dir()?.join(root); | 19 | let root = AbsPathBuf::assert(std::env::current_dir()?.join(root)); |
20 | let root = ProjectManifest::discover_single(&root)?; | 20 | let root = ProjectManifest::discover_single(&root)?; |
21 | let ws = ProjectWorkspace::load( | 21 | let ws = ProjectWorkspace::load( |
22 | root, | 22 | root, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index aa2c4ae15..0be34c43f 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -11,6 +11,7 @@ use std::{ffi::OsString, path::PathBuf}; | |||
11 | 11 | ||
12 | use crate::diagnostics::DiagnosticsConfig; | 12 | use crate::diagnostics::DiagnosticsConfig; |
13 | use lsp_types::ClientCapabilities; | 13 | use lsp_types::ClientCapabilities; |
14 | use ra_db::AbsPathBuf; | ||
14 | use ra_flycheck::FlycheckConfig; | 15 | use ra_flycheck::FlycheckConfig; |
15 | use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; | 16 | use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; |
16 | use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; | 17 | use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; |
@@ -40,7 +41,7 @@ pub struct Config { | |||
40 | 41 | ||
41 | pub with_sysroot: bool, | 42 | pub with_sysroot: bool, |
42 | pub linked_projects: Vec<LinkedProject>, | 43 | pub linked_projects: Vec<LinkedProject>, |
43 | pub root_path: PathBuf, | 44 | pub root_path: AbsPathBuf, |
44 | } | 45 | } |
45 | 46 | ||
46 | #[derive(Debug, Clone)] | 47 | #[derive(Debug, Clone)] |
@@ -131,8 +132,8 @@ pub struct ClientCapsConfig { | |||
131 | pub hover_actions: bool, | 132 | pub hover_actions: bool, |
132 | } | 133 | } |
133 | 134 | ||
134 | impl Default for Config { | 135 | impl Config { |
135 | fn default() -> Self { | 136 | pub fn new(root_path: AbsPathBuf) -> Self { |
136 | Config { | 137 | Config { |
137 | client_caps: ClientCapsConfig::default(), | 138 | client_caps: ClientCapsConfig::default(), |
138 | 139 | ||
@@ -171,18 +172,16 @@ impl Default for Config { | |||
171 | lens: LensConfig::default(), | 172 | lens: LensConfig::default(), |
172 | hover: HoverConfig::default(), | 173 | hover: HoverConfig::default(), |
173 | linked_projects: Vec::new(), | 174 | linked_projects: Vec::new(), |
174 | root_path: PathBuf::new(), | 175 | root_path, |
175 | } | 176 | } |
176 | } | 177 | } |
177 | } | ||
178 | 178 | ||
179 | impl Config { | ||
180 | #[rustfmt::skip] | 179 | #[rustfmt::skip] |
181 | pub fn update(&mut self, value: &serde_json::Value) { | 180 | pub fn update(&mut self, value: &serde_json::Value) { |
182 | log::info!("Config::update({:#})", value); | 181 | log::info!("Config::update({:#})", value); |
183 | 182 | ||
184 | let client_caps = self.client_caps.clone(); | 183 | let client_caps = self.client_caps.clone(); |
185 | *self = Default::default(); | 184 | *self = Config::new(self.root_path.clone()); |
186 | self.client_caps = client_caps; | 185 | self.client_caps = client_caps; |
187 | 186 | ||
188 | set(value, "/withSysroot", &mut self.with_sysroot); | 187 | set(value, "/withSysroot", &mut self.with_sysroot); |
@@ -279,9 +278,12 @@ impl Config { | |||
279 | self.linked_projects.clear(); | 278 | self.linked_projects.clear(); |
280 | for linked_project in linked_projects { | 279 | for linked_project in linked_projects { |
281 | let linked_project = match linked_project { | 280 | let linked_project = match linked_project { |
282 | ManifestOrJsonProject::Manifest(it) => match ProjectManifest::from_manifest_file(it) { | 281 | ManifestOrJsonProject::Manifest(it) => { |
283 | Ok(it) => it.into(), | 282 | let path = self.root_path.join(it); |
284 | Err(_) => continue, | 283 | match ProjectManifest::from_manifest_file(path) { |
284 | Ok(it) => it.into(), | ||
285 | Err(_) => continue, | ||
286 | } | ||
285 | } | 287 | } |
286 | ManifestOrJsonProject::JsonProject(it) => it.into(), | 288 | ManifestOrJsonProject::JsonProject(it) => it.into(), |
287 | }; | 289 | }; |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index e2ddb7933..f18694feb 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -310,11 +310,10 @@ impl ProjectFolders { | |||
310 | 310 | ||
311 | let mut file_set_roots: Vec<VfsPath> = vec![]; | 311 | let mut file_set_roots: Vec<VfsPath> = vec![]; |
312 | 312 | ||
313 | let path = AbsPathBuf::try_from(path).unwrap(); | ||
314 | let entry = if root.is_member() { | 313 | let entry = if root.is_member() { |
315 | vfs::loader::Entry::local_cargo_package(path.clone()) | 314 | vfs::loader::Entry::local_cargo_package(path.to_path_buf()) |
316 | } else { | 315 | } else { |
317 | vfs::loader::Entry::cargo_package_dependency(path.clone()) | 316 | vfs::loader::Entry::cargo_package_dependency(path.to_path_buf()) |
318 | }; | 317 | }; |
319 | res.load.push(entry); | 318 | res.load.push(entry); |
320 | if root.is_member() { | 319 | if root.is_member() { |
@@ -329,7 +328,7 @@ impl ProjectFolders { | |||
329 | } | 328 | } |
330 | file_set_roots.push(out_dir.into()); | 329 | file_set_roots.push(out_dir.into()); |
331 | } | 330 | } |
332 | file_set_roots.push(path.into()); | 331 | file_set_roots.push(path.to_path_buf().into()); |
333 | 332 | ||
334 | if root.is_member() { | 333 | if root.is_member() { |
335 | local_filesets.push(fsc.len()); | 334 | local_filesets.push(fsc.len()); |
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 8d88f992d..49f194f7e 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -17,6 +17,7 @@ use serde_json::{to_string_pretty, Value}; | |||
17 | use tempfile::TempDir; | 17 | use tempfile::TempDir; |
18 | use test_utils::{find_mismatch, Fixture}; | 18 | use test_utils::{find_mismatch, Fixture}; |
19 | 19 | ||
20 | use ra_db::AbsPathBuf; | ||
20 | use ra_project_model::ProjectManifest; | 21 | use ra_project_model::ProjectManifest; |
21 | use rust_analyzer::{ | 22 | use rust_analyzer::{ |
22 | config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, | 23 | config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, |
@@ -70,10 +71,11 @@ impl<'a> Project<'a> { | |||
70 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | 71 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); |
71 | } | 72 | } |
72 | 73 | ||
74 | let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf()); | ||
73 | let mut roots = | 75 | let mut roots = |
74 | self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>(); | 76 | self.roots.into_iter().map(|root| tmp_dir_path.join(root)).collect::<Vec<_>>(); |
75 | if roots.is_empty() { | 77 | if roots.is_empty() { |
76 | roots.push(tmp_dir.path().to_path_buf()); | 78 | roots.push(tmp_dir_path.clone()); |
77 | } | 79 | } |
78 | let linked_projects = roots | 80 | let linked_projects = roots |
79 | .into_iter() | 81 | .into_iter() |
@@ -91,7 +93,7 @@ impl<'a> Project<'a> { | |||
91 | with_sysroot: self.with_sysroot, | 93 | with_sysroot: self.with_sysroot, |
92 | linked_projects, | 94 | linked_projects, |
93 | files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() }, | 95 | files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() }, |
94 | ..Config::default() | 96 | ..Config::new(tmp_dir_path) |
95 | }; | 97 | }; |
96 | if let Some(f) = &self.config { | 98 | if let Some(f) = &self.config { |
97 | f(&mut config) | 99 | f(&mut config) |