aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_project_model/src/lib.rs72
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
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
7use std::{ 7use 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)]
29pub struct CargoTomlNotFoundError(pub PathBuf); 28pub struct CargoTomlNoneFoundError(pub PathBuf);
30 29
31impl std::fmt::Display for CargoTomlNotFoundError { 30#[derive(Clone, PartialEq, Eq, Hash, Debug)]
31pub struct CargoTomlMultipleValidFoundError(pub Vec<PathBuf>);
32
33#[derive(Clone, PartialEq, Eq, Hash, Debug)]
34pub struct CargoTomlSearchFileSystemError(pub PathBuf, pub String);
35
36impl 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
37impl Error for CargoTomlNotFoundError {} 42impl 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
48impl 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
54impl Error for CargoTomlNoneFoundError {}
55impl Error for CargoTomlMultipleValidFoundError {}
56impl Error for CargoTomlSearchFileSystemError {}
38 57
39#[derive(Debug, Clone)] 58#[derive(Debug, Clone)]
40pub enum ProjectWorkspace { 59pub enum ProjectWorkspace {
@@ -407,7 +426,7 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
407 None 426 None
408} 427}
409 428
410fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> { 429fn 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
423fn find_cargo_toml_up_the_fs(path: &Path) -> Option<PathBuf> { 442fn 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
440fn find_cargo_toml(path: &Path) -> Result<PathBuf> { 454fn 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
456pub fn get_rustc_cfg_options() -> CfgOptions { 482pub 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;