Skip to content

Improve filtering of file roots #997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 7 additions & 29 deletions crates/ra_batch/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod vfs_filter;

use std::sync::Arc;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::collections::HashSet;

use rustc_hash::FxHashMap;
Expand All @@ -9,7 +11,8 @@ use ra_db::{
};
use ra_hir::{db, HirInterner};
use ra_project_model::ProjectWorkspace;
use ra_vfs::{Vfs, VfsChange, RootEntry, Filter, RelativePath};
use ra_vfs::{Vfs, VfsChange};
use vfs_filter::IncludeRustFiles;

type Result<T> = std::result::Result<T, failure::Error>;

Expand Down Expand Up @@ -43,30 +46,6 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
SourceRootId(r.0.into())
}

struct IncludeRustFiles;

impl IncludeRustFiles {
fn to_entry(path: PathBuf) -> RootEntry {
RootEntry::new(path, Box::new(Self {}))
}
}

impl Filter for IncludeRustFiles {
fn include_dir(&self, dir_path: &RelativePath) -> bool {
const IGNORED_FOLDERS: &[&str] = &["node_modules", "target", ".git"];

let is_ignored = dir_path.components().any(|c| IGNORED_FOLDERS.contains(&c.as_str()));

let hidden = dir_path.components().any(|c| c.as_str().starts_with("."));

!is_ignored && !hidden
}

fn include_file(&self, file_path: &RelativePath) -> bool {
file_path.extension() == Some("rs")
}
}

impl BatchDatabase {
pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase {
let mut db =
Expand Down Expand Up @@ -122,9 +101,8 @@ impl BatchDatabase {
let root = std::env::current_dir()?.join(root);
let ws = ProjectWorkspace::discover(root.as_ref())?;
let mut roots = Vec::new();
roots.push(root.clone());
roots.extend(ws.to_roots());
let roots = roots.into_iter().map(IncludeRustFiles::to_entry).collect::<Vec<_>>();
roots.push(IncludeRustFiles::member(root.clone()));
roots.extend(IncludeRustFiles::from_roots(ws.to_roots()));
let (mut vfs, roots) = Vfs::new(roots);
let mut load = |path: &Path| {
let vfs_file = vfs.load(path);
Expand Down
54 changes: 54 additions & 0 deletions crates/ra_batch/src/vfs_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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 {
root: ProjectRoot,
}

impl IncludeRustFiles {
pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry>
where
R: IntoIterator<Item = ProjectRoot>,
{
roots.into_iter().map(IncludeRustFiles::from_root)
}

pub fn from_root(root: ProjectRoot) -> RootEntry {
IncludeRustFiles::from(root).into()
}

#[allow(unused)]
pub fn external(path: PathBuf) -> RootEntry {
IncludeRustFiles::from_root(ProjectRoot::new(path, false))
}

pub fn member(path: PathBuf) -> RootEntry {
IncludeRustFiles::from_root(ProjectRoot::new(path, true))
}
}

impl Filter for IncludeRustFiles {
fn include_dir(&self, dir_path: &RelativePath) -> bool {
self.root.include_dir(dir_path)
}

fn include_file(&self, file_path: &RelativePath) -> bool {
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))
}
}
1 change: 1 addition & 0 deletions crates/ra_lsp_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod conv;
mod main_loop;
mod markdown;
mod project_model;
mod vfs_filter;
pub mod req;
pub mod init;
mod server_world;
Expand Down
34 changes: 5 additions & 29 deletions crates/ra_lsp_server/src/server_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ use ra_ide_api::{
Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData,
SourceRootId
};
use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot, RootEntry, Filter};
use relative_path::{RelativePath, RelativePathBuf};
use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot};
use relative_path::RelativePathBuf;
use parking_lot::RwLock;
use failure::format_err;

use crate::{
project_model::ProjectWorkspace,
vfs_filter::IncludeRustFiles,
Result,
};

Expand All @@ -33,40 +34,15 @@ pub struct ServerWorld {
pub vfs: Arc<RwLock<Vfs>>,
}

struct IncludeRustFiles;

impl IncludeRustFiles {
fn to_entry(path: PathBuf) -> RootEntry {
RootEntry::new(path, Box::new(Self {}))
}
}

impl Filter for IncludeRustFiles {
fn include_dir(&self, dir_path: &RelativePath) -> bool {
const IGNORED_FOLDERS: &[&str] = &["node_modules", "target", ".git"];

let is_ignored = dir_path.components().any(|c| IGNORED_FOLDERS.contains(&c.as_str()));

let hidden = dir_path.components().any(|c| c.as_str().starts_with("."));

!is_ignored && !hidden
}

fn include_file(&self, file_path: &RelativePath) -> bool {
file_path.extension() == Some("rs")
}
}

impl ServerWorldState {
pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
let mut change = AnalysisChange::new();

let mut roots = Vec::new();
roots.push(root.clone());
roots.push(IncludeRustFiles::member(root.clone()));
for ws in workspaces.iter() {
roots.extend(ws.to_roots());
roots.extend(IncludeRustFiles::from_roots(ws.to_roots()));
}
let roots = roots.into_iter().map(IncludeRustFiles::to_entry).collect::<Vec<_>>();

let (mut vfs, roots) = Vfs::new(roots);
let roots_to_scan = roots.len();
Expand Down
54 changes: 54 additions & 0 deletions crates/ra_lsp_server/src/vfs_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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 {
root: ProjectRoot,
}

impl IncludeRustFiles {
pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry>
where
R: IntoIterator<Item = ProjectRoot>,
{
roots.into_iter().map(IncludeRustFiles::from_root)
}

pub fn from_root(root: ProjectRoot) -> RootEntry {
IncludeRustFiles::from(root).into()
}

#[allow(unused)]
pub fn external(path: PathBuf) -> RootEntry {
IncludeRustFiles::from_root(ProjectRoot::new(path, false))
}

pub fn member(path: PathBuf) -> RootEntry {
IncludeRustFiles::from_root(ProjectRoot::new(path, true))
}
}

impl Filter for IncludeRustFiles {
fn include_dir(&self, dir_path: &RelativePath) -> bool {
self.root.include_dir(dir_path)
}

fn include_file(&self, file_path: &RelativePath) -> bool {
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))
}
}
1 change: 1 addition & 0 deletions crates/ra_project_model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
61 changes: 57 additions & 4 deletions crates/ra_project_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -32,6 +34,52 @@ pub enum ProjectWorkspace {
Json { project: JsonProject },
}

/// `ProjectRoot` describes a workspace root folder.
/// Which may be an external dependency, or a member of
/// the current workspace.
pub struct ProjectRoot {
/// Path to the root folder
path: PathBuf,
/// Is a member of the current workspace
is_member: bool,
}

impl ProjectRoot {
pub fn new(path: PathBuf, is_member: bool) -> ProjectRoot {
ProjectRoot { path, is_member }
}

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 {
pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
match find_rust_project_json(path) {
Expand All @@ -50,23 +98,28 @@ impl ProjectWorkspace {
}
}

pub fn to_roots(&self) -> Vec<PathBuf> {
/// Returns the roots for the current ProjectWorkspace
/// The return type contains the path and whether or not
/// the root is a member of the current workspace
pub fn to_roots(&self) -> Vec<ProjectRoot> {
match self {
ProjectWorkspace::Json { project } => {
let mut roots = Vec::with_capacity(project.roots.len());
for root in &project.roots {
roots.push(root.path.clone());
roots.push(ProjectRoot::new(root.path.clone(), true));
}
roots
}
ProjectWorkspace::Cargo { cargo, sysroot } => {
let mut roots =
Vec::with_capacity(cargo.packages().count() + sysroot.crates().count());
for pkg in cargo.packages() {
roots.push(pkg.root(&cargo).to_path_buf());
let root = pkg.root(&cargo).to_path_buf();
let member = pkg.is_member(&cargo);
roots.push(ProjectRoot::new(root, member));
}
for krate in sysroot.crates() {
roots.push(krate.root_dir(&sysroot).to_path_buf())
roots.push(ProjectRoot::new(krate.root_dir(&sysroot).to_path_buf(), false))
}
roots
}
Expand Down