From c6d6e6c6259709ec30eadb79a1908dca707a6499 Mon Sep 17 00:00:00 2001
From: Ville Penttinen <villem.penttinen@gmail.com>
Date: Thu, 21 Mar 2019 10:43:47 +0200
Subject: [PATCH] Move actual include logic to ProjectRoot

This way the two IncludeRustFiles implementations can simply call the
ProjectRoots' methods, so that the include logic is in one place.
---
 Cargo.lock                             |  1 +
 crates/ra_batch/src/vfs_filter.rs      | 47 ++++++++++++--------------
 crates/ra_lsp_server/src/vfs_filter.rs | 47 ++++++++++++--------------
 crates/ra_project_model/Cargo.toml     |  1 +
 crates/ra_project_model/src/lib.rs     | 30 ++++++++++++++--
 5 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index ad9f6970b39..55bef8cb9e7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1088,6 +1088,7 @@ dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_arena 0.1.0",
  "ra_db 0.1.0",
+ "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/crates/ra_batch/src/vfs_filter.rs b/crates/ra_batch/src/vfs_filter.rs
index 290aec1728e..dd20c12031f 100644
--- a/crates/ra_batch/src/vfs_filter.rs
+++ b/crates/ra_batch/src/vfs_filter.rs
@@ -2,9 +2,10 @@ use std::path::PathBuf;
 use ra_project_model::ProjectRoot;
 use ra_vfs::{RootEntry, Filter, RelativePath};
 
+/// `IncludeRustFiles` is used to convert
+/// from `ProjectRoot` to `RootEntry` for VFS
 pub struct IncludeRustFiles {
-    /// Is a member of the current workspace
-    is_member: bool,
+    root: ProjectRoot,
 }
 
 impl IncludeRustFiles {
@@ -16,44 +17,38 @@ impl IncludeRustFiles {
     }
 
     pub fn from_root(root: ProjectRoot) -> RootEntry {
-        let is_member = root.is_member();
-        IncludeRustFiles::into_entry(root.into_path(), is_member)
+        IncludeRustFiles::from(root).into()
     }
 
     #[allow(unused)]
     pub fn external(path: PathBuf) -> RootEntry {
-        IncludeRustFiles::into_entry(path, false)
+        IncludeRustFiles::from_root(ProjectRoot::new(path, false))
     }
 
     pub fn member(path: PathBuf) -> RootEntry {
-        IncludeRustFiles::into_entry(path, true)
-    }
-
-    fn into_entry(path: PathBuf, is_member: bool) -> RootEntry {
-        RootEntry::new(path, Box::new(Self { is_member }))
+        IncludeRustFiles::from_root(ProjectRoot::new(path, true))
     }
 }
 
 impl Filter for IncludeRustFiles {
     fn include_dir(&self, dir_path: &RelativePath) -> bool {
-        const COMMON_IGNORED_DIRS: &[&str] = &["node_modules", "target", ".git"];
-        const EXTERNAL_IGNORED_DIRS: &[&str] = &["examples", "tests", "benches"];
-
-        let is_ignored = if self.is_member {
-            dir_path.components().any(|c| COMMON_IGNORED_DIRS.contains(&c.as_str()))
-        } else {
-            dir_path.components().any(|c| {
-                let path = c.as_str();
-                COMMON_IGNORED_DIRS.contains(&path) || EXTERNAL_IGNORED_DIRS.contains(&path)
-            })
-        };
-
-        let hidden = dir_path.components().any(|c| c.as_str().starts_with("."));
-
-        !is_ignored && !hidden
+        self.root.include_dir(dir_path)
     }
 
     fn include_file(&self, file_path: &RelativePath) -> bool {
-        file_path.extension() == Some("rs")
+        self.root.include_file(file_path)
+    }
+}
+
+impl std::convert::From<ProjectRoot> for IncludeRustFiles {
+    fn from(v: ProjectRoot) -> IncludeRustFiles {
+        IncludeRustFiles { root: v }
+    }
+}
+
+impl std::convert::From<IncludeRustFiles> for RootEntry {
+    fn from(v: IncludeRustFiles) -> RootEntry {
+        let path = v.root.path().clone();
+        RootEntry::new(path, Box::new(v))
     }
 }
diff --git a/crates/ra_lsp_server/src/vfs_filter.rs b/crates/ra_lsp_server/src/vfs_filter.rs
index 290aec1728e..dd20c12031f 100644
--- a/crates/ra_lsp_server/src/vfs_filter.rs
+++ b/crates/ra_lsp_server/src/vfs_filter.rs
@@ -2,9 +2,10 @@ use std::path::PathBuf;
 use ra_project_model::ProjectRoot;
 use ra_vfs::{RootEntry, Filter, RelativePath};
 
+/// `IncludeRustFiles` is used to convert
+/// from `ProjectRoot` to `RootEntry` for VFS
 pub struct IncludeRustFiles {
-    /// Is a member of the current workspace
-    is_member: bool,
+    root: ProjectRoot,
 }
 
 impl IncludeRustFiles {
@@ -16,44 +17,38 @@ impl IncludeRustFiles {
     }
 
     pub fn from_root(root: ProjectRoot) -> RootEntry {
-        let is_member = root.is_member();
-        IncludeRustFiles::into_entry(root.into_path(), is_member)
+        IncludeRustFiles::from(root).into()
     }
 
     #[allow(unused)]
     pub fn external(path: PathBuf) -> RootEntry {
-        IncludeRustFiles::into_entry(path, false)
+        IncludeRustFiles::from_root(ProjectRoot::new(path, false))
     }
 
     pub fn member(path: PathBuf) -> RootEntry {
-        IncludeRustFiles::into_entry(path, true)
-    }
-
-    fn into_entry(path: PathBuf, is_member: bool) -> RootEntry {
-        RootEntry::new(path, Box::new(Self { is_member }))
+        IncludeRustFiles::from_root(ProjectRoot::new(path, true))
     }
 }
 
 impl Filter for IncludeRustFiles {
     fn include_dir(&self, dir_path: &RelativePath) -> bool {
-        const COMMON_IGNORED_DIRS: &[&str] = &["node_modules", "target", ".git"];
-        const EXTERNAL_IGNORED_DIRS: &[&str] = &["examples", "tests", "benches"];
-
-        let is_ignored = if self.is_member {
-            dir_path.components().any(|c| COMMON_IGNORED_DIRS.contains(&c.as_str()))
-        } else {
-            dir_path.components().any(|c| {
-                let path = c.as_str();
-                COMMON_IGNORED_DIRS.contains(&path) || EXTERNAL_IGNORED_DIRS.contains(&path)
-            })
-        };
-
-        let hidden = dir_path.components().any(|c| c.as_str().starts_with("."));
-
-        !is_ignored && !hidden
+        self.root.include_dir(dir_path)
     }
 
     fn include_file(&self, file_path: &RelativePath) -> bool {
-        file_path.extension() == Some("rs")
+        self.root.include_file(file_path)
+    }
+}
+
+impl std::convert::From<ProjectRoot> for IncludeRustFiles {
+    fn from(v: ProjectRoot) -> IncludeRustFiles {
+        IncludeRustFiles { root: v }
+    }
+}
+
+impl std::convert::From<IncludeRustFiles> for RootEntry {
+    fn from(v: IncludeRustFiles) -> RootEntry {
+        let path = v.root.path().clone();
+        RootEntry::new(path, Box::new(v))
     }
 }
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index 34d33531eb8..cf4adf35cd5 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -7,6 +7,7 @@ authors = ["rust-analyzer developers"]
 [dependencies]
 log = "0.4.5"
 rustc-hash = "1.0"
+relative-path = "0.4.0"
 
 failure = "0.1.4"
 
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index b27cb55effd..6f46a2d4350 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -15,6 +15,8 @@ use ra_db::{CrateGraph, FileId, Edition};
 
 use serde_json::from_reader;
 
+use relative_path::RelativePath;
+
 pub use crate::{
     cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
     json_project::JsonProject,
@@ -43,17 +45,39 @@ pub struct ProjectRoot {
 }
 
 impl ProjectRoot {
-    fn new(path: PathBuf, is_member: bool) -> ProjectRoot {
+    pub fn new(path: PathBuf, is_member: bool) -> ProjectRoot {
         ProjectRoot { path, is_member }
     }
 
-    pub fn into_path(self) -> PathBuf {
-        self.path
+    pub fn path(&self) -> &PathBuf {
+        &self.path
     }
 
     pub fn is_member(&self) -> bool {
         self.is_member
     }
+
+    pub fn include_dir(&self, dir_path: &RelativePath) -> bool {
+        const COMMON_IGNORED_DIRS: &[&str] = &["node_modules", "target", ".git"];
+        const EXTERNAL_IGNORED_DIRS: &[&str] = &["examples", "tests", "benches"];
+
+        let is_ignored = if self.is_member {
+            dir_path.components().any(|c| COMMON_IGNORED_DIRS.contains(&c.as_str()))
+        } else {
+            dir_path.components().any(|c| {
+                let path = c.as_str();
+                COMMON_IGNORED_DIRS.contains(&path) || EXTERNAL_IGNORED_DIRS.contains(&path)
+            })
+        };
+
+        let hidden = dir_path.components().any(|c| c.as_str().starts_with("."));
+
+        !is_ignored && !hidden
+    }
+
+    pub fn include_file(&self, file_path: &RelativePath) -> bool {
+        file_path.extension() == Some("rs")
+    }
 }
 
 impl ProjectWorkspace {