mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-02 19:53:46 +00:00
move roots to a module
This commit is contained in:
parent
f937d11ad8
commit
6b5d90972a
@ -15,10 +15,10 @@
|
|||||||
//! VFS is based on a concept of roots: a set of directories on the file system
|
//! VFS is based on a concept of roots: a set of directories on the file system
|
||||||
//! which are watched for changes. Typically, there will be a root for each
|
//! which are watched for changes. Typically, there will be a root for each
|
||||||
//! Cargo package.
|
//! Cargo package.
|
||||||
|
mod roots;
|
||||||
mod io;
|
mod io;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Reverse,
|
|
||||||
fmt, fs, mem,
|
fmt, fs, mem,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@ -26,106 +26,18 @@ use std::{
|
|||||||
|
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap};
|
use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap};
|
||||||
use relative_path::{Component, RelativePath, RelativePathBuf};
|
use relative_path::{RelativePath, RelativePathBuf};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
pub use crate::io::TaskResult as VfsTask;
|
use crate::{
|
||||||
use io::{TaskResult, Worker};
|
io::{TaskResult, Worker},
|
||||||
|
roots::{RootConfig, Roots},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
pub use crate::{
|
||||||
pub struct VfsRoot(pub RawId);
|
io::TaskResult as VfsTask,
|
||||||
impl_arena_id!(VfsRoot);
|
roots::VfsRoot,
|
||||||
|
};
|
||||||
/// Describes the contents of a single source root.
|
|
||||||
///
|
|
||||||
/// `RootConfig` can be thought of as a glob pattern like `src/**.rs` which
|
|
||||||
/// specifies the source root or as a function which takes a `PathBuf` and
|
|
||||||
/// returns `true` iff path belongs to the source root
|
|
||||||
pub(crate) struct RootConfig {
|
|
||||||
root: PathBuf,
|
|
||||||
// result of `root.canonicalize()` if that differs from `root`; `None` otherwise.
|
|
||||||
canonical_root: Option<PathBuf>,
|
|
||||||
excluded_dirs: Vec<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct Roots {
|
|
||||||
roots: Arena<VfsRoot, Arc<RootConfig>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for Roots {
|
|
||||||
type Target = Arena<VfsRoot, Arc<RootConfig>>;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.roots
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RootConfig {
|
|
||||||
fn new(root: PathBuf, excluded_dirs: Vec<PathBuf>) -> RootConfig {
|
|
||||||
let mut canonical_root = root.canonicalize().ok();
|
|
||||||
if Some(&root) == canonical_root.as_ref() {
|
|
||||||
canonical_root = None;
|
|
||||||
}
|
|
||||||
RootConfig { root, canonical_root, excluded_dirs }
|
|
||||||
}
|
|
||||||
/// Checks if root contains a path and returns a root-relative path.
|
|
||||||
pub(crate) fn contains(&self, path: &Path) -> Option<RelativePathBuf> {
|
|
||||||
// First, check excluded dirs
|
|
||||||
if self.excluded_dirs.iter().any(|it| path.starts_with(it)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let rel_path = path
|
|
||||||
.strip_prefix(&self.root)
|
|
||||||
.or_else(|err_payload| {
|
|
||||||
self.canonical_root
|
|
||||||
.as_ref()
|
|
||||||
.map_or(Err(err_payload), |canonical_root| path.strip_prefix(canonical_root))
|
|
||||||
})
|
|
||||||
.ok()?;
|
|
||||||
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
|
||||||
|
|
||||||
// Ignore some common directories.
|
|
||||||
//
|
|
||||||
// FIXME: don't hard-code, specify at source-root creation time using
|
|
||||||
// gitignore
|
|
||||||
for (i, c) in rel_path.components().enumerate() {
|
|
||||||
if let Component::Normal(c) = c {
|
|
||||||
if (i == 0 && c == "target") || c == ".git" || c == "node_modules" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if path.is_file() && rel_path.extension() != Some("rs") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(rel_path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Roots {
|
|
||||||
pub(crate) fn new(mut paths: Vec<PathBuf>) -> Roots {
|
|
||||||
let mut roots = Arena::default();
|
|
||||||
// A hack to make nesting work.
|
|
||||||
paths.sort_by_key(|it| Reverse(it.as_os_str().len()));
|
|
||||||
paths.dedup();
|
|
||||||
for (i, path) in paths.iter().enumerate() {
|
|
||||||
let nested_roots = paths[..i]
|
|
||||||
.iter()
|
|
||||||
.filter(|it| it.starts_with(path))
|
|
||||||
.map(|it| it.clone())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let config = Arc::new(RootConfig::new(path.clone(), nested_roots));
|
|
||||||
|
|
||||||
roots.alloc(config.clone());
|
|
||||||
}
|
|
||||||
Roots { roots }
|
|
||||||
}
|
|
||||||
pub(crate) fn find(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf)> {
|
|
||||||
self.roots.iter().find_map(|(root, data)| data.contains(path).map(|it| (root, it)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct VfsFile(pub RawId);
|
pub struct VfsFile(pub RawId);
|
||||||
|
102
crates/ra_vfs/src/roots.rs
Normal file
102
crates/ra_vfs/src/roots.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
use ra_arena::{impl_arena_id, Arena, RawId};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct VfsRoot(pub RawId);
|
||||||
|
impl_arena_id!(VfsRoot);
|
||||||
|
|
||||||
|
/// Describes the contents of a single source root.
|
||||||
|
///
|
||||||
|
/// `RootConfig` can be thought of as a glob pattern like `src/**.rs` which
|
||||||
|
/// specifies the source root or as a function which takes a `PathBuf` and
|
||||||
|
/// returns `true` iff path belongs to the source root
|
||||||
|
pub(crate) struct RootConfig {
|
||||||
|
pub(crate) root: PathBuf,
|
||||||
|
// result of `root.canonicalize()` if that differs from `root`; `None` otherwise.
|
||||||
|
canonical_root: Option<PathBuf>,
|
||||||
|
excluded_dirs: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Roots {
|
||||||
|
roots: Arena<VfsRoot, Arc<RootConfig>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for Roots {
|
||||||
|
type Target = Arena<VfsRoot, Arc<RootConfig>>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.roots
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RootConfig {
|
||||||
|
fn new(root: PathBuf, excluded_dirs: Vec<PathBuf>) -> RootConfig {
|
||||||
|
let mut canonical_root = root.canonicalize().ok();
|
||||||
|
if Some(&root) == canonical_root.as_ref() {
|
||||||
|
canonical_root = None;
|
||||||
|
}
|
||||||
|
RootConfig { root, canonical_root, excluded_dirs }
|
||||||
|
}
|
||||||
|
/// Checks if root contains a path and returns a root-relative path.
|
||||||
|
pub(crate) fn contains(&self, path: &Path) -> Option<RelativePathBuf> {
|
||||||
|
// First, check excluded dirs
|
||||||
|
if self.excluded_dirs.iter().any(|it| path.starts_with(it)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let rel_path = path
|
||||||
|
.strip_prefix(&self.root)
|
||||||
|
.or_else(|err_payload| {
|
||||||
|
self.canonical_root
|
||||||
|
.as_ref()
|
||||||
|
.map_or(Err(err_payload), |canonical_root| path.strip_prefix(canonical_root))
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
|
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
||||||
|
|
||||||
|
// Ignore some common directories.
|
||||||
|
//
|
||||||
|
// FIXME: don't hard-code, specify at source-root creation time using
|
||||||
|
// gitignore
|
||||||
|
for (i, c) in rel_path.components().enumerate() {
|
||||||
|
if let relative_path::Component::Normal(c) = c {
|
||||||
|
if (i == 0 && c == "target") || c == ".git" || c == "node_modules" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.is_file() && rel_path.extension() != Some("rs") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(rel_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Roots {
|
||||||
|
pub(crate) fn new(mut paths: Vec<PathBuf>) -> Roots {
|
||||||
|
let mut roots = Arena::default();
|
||||||
|
// A hack to make nesting work.
|
||||||
|
paths.sort_by_key(|it| std::cmp::Reverse(it.as_os_str().len()));
|
||||||
|
paths.dedup();
|
||||||
|
for (i, path) in paths.iter().enumerate() {
|
||||||
|
let nested_roots = paths[..i]
|
||||||
|
.iter()
|
||||||
|
.filter(|it| it.starts_with(path))
|
||||||
|
.map(|it| it.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let config = Arc::new(RootConfig::new(path.clone(), nested_roots));
|
||||||
|
|
||||||
|
roots.alloc(config.clone());
|
||||||
|
}
|
||||||
|
Roots { roots }
|
||||||
|
}
|
||||||
|
pub(crate) fn find(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf)> {
|
||||||
|
self.roots.iter().find_map(|(root, data)| data.contains(path).map(|it| (root, it)))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user