diff options
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 72 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 2 |
2 files changed, 50 insertions, 24 deletions
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index cfebf36f8..f678bf5d6 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -6,8 +6,7 @@ mod sysroot; | |||
6 | 6 | ||
7 | use std::{ | 7 | use std::{ |
8 | error::Error, | 8 | error::Error, |
9 | fs::File, | 9 | fs::{read_dir, File, ReadDir}, |
10 | fs::read_dir, | ||
11 | io::BufReader, | 10 | io::BufReader, |
12 | path::{Path, PathBuf}, | 11 | path::{Path, PathBuf}, |
13 | process::Command, | 12 | process::Command, |
@@ -26,15 +25,35 @@ pub use crate::{ | |||
26 | }; | 25 | }; |
27 | 26 | ||
28 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 27 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
29 | pub struct CargoTomlNotFoundError(pub PathBuf); | 28 | pub struct CargoTomlNoneFoundError(pub PathBuf); |
30 | 29 | ||
31 | impl std::fmt::Display for CargoTomlNotFoundError { | 30 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
31 | pub struct CargoTomlMultipleValidFoundError(pub Vec<PathBuf>); | ||
32 | |||
33 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
34 | pub struct CargoTomlSearchFileSystemError(pub PathBuf, pub String); | ||
35 | |||
36 | impl std::fmt::Display for CargoTomlNoneFoundError { | ||
32 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 37 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
33 | write!(fmt, "can't find Cargo.toml at {}", self.0.display()) | 38 | write!(fmt, "can't find Cargo.toml at {}", self.0.display()) |
34 | } | 39 | } |
35 | } | 40 | } |
36 | 41 | ||
37 | impl Error for CargoTomlNotFoundError {} | 42 | impl std::fmt::Display for CargoTomlMultipleValidFoundError { |
43 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
44 | write!(fmt, "found multiple valid Cargo.toml files {:?}", self.0) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | impl std::fmt::Display for CargoTomlSearchFileSystemError { | ||
49 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
50 | write!(fmt, "a filesystem error occurred while searching for Cargo.toml: {}", self.1) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | impl Error for CargoTomlNoneFoundError {} | ||
55 | impl Error for CargoTomlMultipleValidFoundError {} | ||
56 | impl Error for CargoTomlSearchFileSystemError {} | ||
38 | 57 | ||
39 | #[derive(Debug, Clone)] | 58 | #[derive(Debug, Clone)] |
40 | pub enum ProjectWorkspace { | 59 | pub enum ProjectWorkspace { |
@@ -407,7 +426,7 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> { | |||
407 | None | 426 | None |
408 | } | 427 | } |
409 | 428 | ||
410 | fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> { | 429 | fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> { |
411 | let mut curr = Some(path); | 430 | let mut curr = Some(path); |
412 | while let Some(path) = curr { | 431 | while let Some(path) = curr { |
413 | let candidate = path.join("Cargo.toml"); | 432 | let candidate = path.join("Cargo.toml"); |
@@ -416,41 +435,48 @@ fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> { | |||
416 | } | 435 | } |
417 | curr = path.parent(); | 436 | curr = path.parent(); |
418 | } | 437 | } |
419 | 438 | ||
420 | None | 439 | None |
421 | } | 440 | } |
422 | 441 | ||
423 | fn find_cargo_toml_up_the_fs(path: &Path) -> Option<PathBuf> { | 442 | fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> { |
424 | let entities = match read_dir(path) { | 443 | // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects |
425 | Ok(entities) => entities, | 444 | let mut valid_canditates = vec![]; |
426 | Err(_) => return None | ||
427 | }; | ||
428 | |||
429 | // Only one level up to avoid cycles the easy way and stop a runaway scan with large projects | ||
430 | for entity in entities.filter_map(Result::ok) { | 445 | for entity in entities.filter_map(Result::ok) { |
431 | let candidate = entity.path().join("Cargo.toml"); | 446 | let candidate = entity.path().join("Cargo.toml"); |
432 | if candidate.exists() { | 447 | if candidate.exists() { |
433 | return Some(candidate); | 448 | valid_canditates.push(candidate) |
434 | } | 449 | } |
435 | } | 450 | } |
436 | 451 | valid_canditates | |
437 | None | ||
438 | } | 452 | } |
439 | 453 | ||
440 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | 454 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { |
455 | let path_as_buf = path.to_path_buf(); | ||
456 | |||
441 | if path.ends_with("Cargo.toml") { | 457 | if path.ends_with("Cargo.toml") { |
442 | return Ok(path.to_path_buf()); | 458 | return Ok(path.to_path_buf()); |
443 | } | 459 | } |
444 | 460 | ||
445 | if let Some(p) = find_cargo_toml_down_the_fs(path) { | 461 | if let Some(p) = find_cargo_toml_in_parent_dir(path) { |
446 | return Ok(p) | 462 | return Ok(p); |
447 | } | 463 | } |
448 | 464 | ||
449 | if let Some(p) = find_cargo_toml_up_the_fs(path) { | 465 | let entities = match read_dir(path.join("does_not_exist")) { |
450 | return Ok(p) | 466 | Ok(entities) => { |
451 | } | 467 | entities |
468 | }, | ||
469 | Err(e) => { | ||
470 | return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into()) | ||
471 | }, | ||
472 | }; | ||
452 | 473 | ||
453 | Err(CargoTomlNotFoundError(path.to_path_buf()).into()) | 474 | let mut valid_canditates = find_cargo_toml_in_child_dir(entities); |
475 | match valid_canditates.len() { | ||
476 | 1 => Ok(valid_canditates.remove(0)), | ||
477 | 0 => Err(CargoTomlNoneFoundError(path_as_buf).into()), | ||
478 | _ => Err(CargoTomlMultipleValidFoundError(valid_canditates).into()), | ||
479 | } | ||
454 | } | 480 | } |
455 | 481 | ||
456 | pub fn get_rustc_cfg_options() -> CfgOptions { | 482 | pub fn get_rustc_cfg_options() -> CfgOptions { |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 6e9e604a6..37a46cd65 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -115,7 +115,7 @@ pub fn main_loop( | |||
115 | Ok(workspace) => loaded_workspaces.push(workspace), | 115 | Ok(workspace) => loaded_workspaces.push(workspace), |
116 | Err(e) => { | 116 | Err(e) => { |
117 | log::error!("loading workspace failed: {:?}", e); | 117 | log::error!("loading workspace failed: {:?}", e); |
118 | if let Some(ra_project_model::CargoTomlNotFoundError(_)) = e.downcast_ref() | 118 | if let Some(ra_project_model::CargoTomlNoneFoundError(_)) = e.downcast_ref() |
119 | { | 119 | { |
120 | if !feature_flags.get("notifications.cargo-toml-not-found") { | 120 | if !feature_flags.get("notifications.cargo-toml-not-found") { |
121 | continue; | 121 | continue; |