aboutsummaryrefslogtreecommitdiff
path: root/crates/vfs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-11 10:04:09 +0100
committerAleksey Kladov <[email protected]>2020-06-23 16:51:06 +0100
commitdad1333b48c38bc7a5628fc0ff5304d003776a85 (patch)
tree29be52a980b4cae72f46a48c48135a15e31641e0 /crates/vfs
parent7aa66371ee3e8b31217513204c8b4f683584419d (diff)
New VFS
Diffstat (limited to 'crates/vfs')
-rw-r--r--crates/vfs/Cargo.toml4
-rw-r--r--crates/vfs/src/file_set.rs15
-rw-r--r--crates/vfs/src/lib.rs1
-rw-r--r--crates/vfs/src/loader.rs22
-rw-r--r--crates/vfs/src/vfs_path.rs51
-rw-r--r--crates/vfs/src/walkdir_loader.rs108
6 files changed, 67 insertions, 134 deletions
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index c03e6363b..263069002 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -6,9 +6,5 @@ edition = "2018"
6 6
7[dependencies] 7[dependencies]
8rustc-hash = "1.0" 8rustc-hash = "1.0"
9jod-thread = "0.1.0"
10walkdir = "2.3.1"
11globset = "0.4.5"
12crossbeam-channel = "0.4.0"
13 9
14paths = { path = "../paths" } 10paths = { path = "../paths" }
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
index 724606a3d..0173f7464 100644
--- a/crates/vfs/src/file_set.rs
+++ b/crates/vfs/src/file_set.rs
@@ -4,7 +4,6 @@
4//! the default `FileSet`. 4//! the default `FileSet`.
5use std::{fmt, iter}; 5use std::{fmt, iter};
6 6
7use paths::AbsPathBuf;
8use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
9 8
10use crate::{FileId, Vfs, VfsPath}; 9use crate::{FileId, Vfs, VfsPath};
@@ -41,7 +40,7 @@ impl fmt::Debug for FileSet {
41#[derive(Debug)] 40#[derive(Debug)]
42pub struct FileSetConfig { 41pub struct FileSetConfig {
43 n_file_sets: usize, 42 n_file_sets: usize,
44 roots: Vec<(AbsPathBuf, usize)>, 43 roots: Vec<(VfsPath, usize)>,
45} 44}
46 45
47impl Default for FileSetConfig { 46impl Default for FileSetConfig {
@@ -66,11 +65,7 @@ impl FileSetConfig {
66 self.n_file_sets 65 self.n_file_sets
67 } 66 }
68 fn classify(&self, path: &VfsPath) -> usize { 67 fn classify(&self, path: &VfsPath) -> usize {
69 let path = match path.as_path() { 68 let idx = match self.roots.binary_search_by(|(p, _)| p.cmp(path)) {
70 Some(it) => it,
71 None => return self.len() - 1,
72 };
73 let idx = match self.roots.binary_search_by(|(p, _)| p.as_path().cmp(path)) {
74 Ok(it) => it, 69 Ok(it) => it,
75 Err(it) => it.saturating_sub(1), 70 Err(it) => it.saturating_sub(1),
76 }; 71 };
@@ -83,7 +78,7 @@ impl FileSetConfig {
83} 78}
84 79
85pub struct FileSetConfigBuilder { 80pub struct FileSetConfigBuilder {
86 roots: Vec<Vec<AbsPathBuf>>, 81 roots: Vec<Vec<VfsPath>>,
87} 82}
88 83
89impl Default for FileSetConfigBuilder { 84impl Default for FileSetConfigBuilder {
@@ -96,12 +91,12 @@ impl FileSetConfigBuilder {
96 pub fn len(&self) -> usize { 91 pub fn len(&self) -> usize {
97 self.roots.len() 92 self.roots.len()
98 } 93 }
99 pub fn add_file_set(&mut self, roots: Vec<AbsPathBuf>) { 94 pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
100 self.roots.push(roots) 95 self.roots.push(roots)
101 } 96 }
102 pub fn build(self) -> FileSetConfig { 97 pub fn build(self) -> FileSetConfig {
103 let n_file_sets = self.roots.len() + 1; 98 let n_file_sets = self.roots.len() + 1;
104 let mut roots: Vec<(AbsPathBuf, usize)> = self 99 let mut roots: Vec<(VfsPath, usize)> = self
105 .roots 100 .roots
106 .into_iter() 101 .into_iter()
107 .enumerate() 102 .enumerate()
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index 055219b0c..024e58018 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -38,7 +38,6 @@ mod vfs_path;
38mod path_interner; 38mod path_interner;
39pub mod file_set; 39pub mod file_set;
40pub mod loader; 40pub mod loader;
41pub mod walkdir_loader;
42 41
43use std::{fmt, mem}; 42use std::{fmt, mem};
44 43
diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs
index 5a0ca68f3..a216b5f13 100644
--- a/crates/vfs/src/loader.rs
+++ b/crates/vfs/src/loader.rs
@@ -3,19 +3,20 @@ use std::fmt;
3 3
4use paths::AbsPathBuf; 4use paths::AbsPathBuf;
5 5
6#[derive(Debug)]
6pub enum Entry { 7pub enum Entry {
7 Files(Vec<AbsPathBuf>), 8 Files(Vec<AbsPathBuf>),
8 Directory { path: AbsPathBuf, globs: Vec<String> }, 9 Directory { path: AbsPathBuf, include: Vec<String> },
9} 10}
10 11
12#[derive(Debug)]
11pub struct Config { 13pub struct Config {
12 pub load: Vec<Entry>, 14 pub load: Vec<Entry>,
13 pub watch: Vec<usize>, 15 pub watch: Vec<usize>,
14} 16}
15 17
16pub enum Message { 18pub enum Message {
17 DidSwitchConfig { n_entries: usize }, 19 Progress { n_entries_total: usize, n_entries_done: usize },
18 DidLoadAllEntries,
19 Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> }, 20 Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
20} 21}
21 22
@@ -32,15 +33,15 @@ pub trait Handle: fmt::Debug {
32 33
33impl Entry { 34impl Entry {
34 pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { 35 pub fn rs_files_recursively(base: AbsPathBuf) -> Entry {
35 Entry::Directory { path: base, globs: globs(&["*.rs"]) } 36 Entry::Directory { path: base, include: globs(&["*.rs", "!/.git/"]) }
36 } 37 }
37 pub fn local_cargo_package(base: AbsPathBuf) -> Entry { 38 pub fn local_cargo_package(base: AbsPathBuf) -> Entry {
38 Entry::Directory { path: base, globs: globs(&["*.rs", "!/target/"]) } 39 Entry::Directory { path: base, include: globs(&["*.rs", "!/target/", "!/.git/"]) }
39 } 40 }
40 pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { 41 pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry {
41 Entry::Directory { 42 Entry::Directory {
42 path: base, 43 path: base,
43 globs: globs(&["*.rs", "!/tests/", "!/examples/", "!/benches/"]), 44 include: globs(&["*.rs", "!/tests/", "!/examples/", "!/benches/", "!/.git/"]),
44 } 45 }
45 } 46 }
46} 47}
@@ -55,10 +56,11 @@ impl fmt::Debug for Message {
55 Message::Loaded { files } => { 56 Message::Loaded { files } => {
56 f.debug_struct("Loaded").field("n_files", &files.len()).finish() 57 f.debug_struct("Loaded").field("n_files", &files.len()).finish()
57 } 58 }
58 Message::DidSwitchConfig { n_entries } => { 59 Message::Progress { n_entries_total, n_entries_done } => f
59 f.debug_struct("DidSwitchConfig").field("n_entries", n_entries).finish() 60 .debug_struct("Progress")
60 } 61 .field("n_entries_total", n_entries_total)
61 Message::DidLoadAllEntries => f.debug_struct("DidLoadAllEntries").finish(), 62 .field("n_entries_done", n_entries_done)
63 .finish(),
62 } 64 }
63 } 65 }
64} 66}
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs
index de5dc0bf3..0a8a86c62 100644
--- a/crates/vfs/src/vfs_path.rs
+++ b/crates/vfs/src/vfs_path.rs
@@ -9,9 +9,17 @@ use paths::{AbsPath, AbsPathBuf};
9pub struct VfsPath(VfsPathRepr); 9pub struct VfsPath(VfsPathRepr);
10 10
11impl VfsPath { 11impl VfsPath {
12 /// Creates an "in-memory" path from `/`-separates string.
13 /// This is most useful for testing, to avoid windows/linux differences
14 pub fn new_virtual_path(path: String) -> VfsPath {
15 assert!(path.starts_with('/'));
16 VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path)))
17 }
18
12 pub fn as_path(&self) -> Option<&AbsPath> { 19 pub fn as_path(&self) -> Option<&AbsPath> {
13 match &self.0 { 20 match &self.0 {
14 VfsPathRepr::PathBuf(it) => Some(it.as_path()), 21 VfsPathRepr::PathBuf(it) => Some(it.as_path()),
22 VfsPathRepr::VirtualPath(_) => None,
15 } 23 }
16 } 24 }
17 pub fn join(&self, path: &str) -> VfsPath { 25 pub fn join(&self, path: &str) -> VfsPath {
@@ -20,11 +28,24 @@ impl VfsPath {
20 let res = it.join(path).normalize(); 28 let res = it.join(path).normalize();
21 VfsPath(VfsPathRepr::PathBuf(res)) 29 VfsPath(VfsPathRepr::PathBuf(res))
22 } 30 }
31 VfsPathRepr::VirtualPath(it) => {
32 let res = it.join(path);
33 VfsPath(VfsPathRepr::VirtualPath(res))
34 }
23 } 35 }
24 } 36 }
25 pub fn pop(&mut self) -> bool { 37 pub fn pop(&mut self) -> bool {
26 match &mut self.0 { 38 match &mut self.0 {
27 VfsPathRepr::PathBuf(it) => it.pop(), 39 VfsPathRepr::PathBuf(it) => it.pop(),
40 VfsPathRepr::VirtualPath(it) => it.pop(),
41 }
42 }
43 pub fn starts_with(&self, other: &VfsPath) -> bool {
44 match (&self.0, &other.0) {
45 (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs),
46 (VfsPathRepr::PathBuf(_), _) => false,
47 (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs),
48 (VfsPathRepr::VirtualPath(_), _) => false,
28 } 49 }
29 } 50 }
30} 51}
@@ -32,11 +53,12 @@ impl VfsPath {
32#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] 53#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
33enum VfsPathRepr { 54enum VfsPathRepr {
34 PathBuf(AbsPathBuf), 55 PathBuf(AbsPathBuf),
56 VirtualPath(VirtualPath),
35} 57}
36 58
37impl From<AbsPathBuf> for VfsPath { 59impl From<AbsPathBuf> for VfsPath {
38 fn from(v: AbsPathBuf) -> Self { 60 fn from(v: AbsPathBuf) -> Self {
39 VfsPath(VfsPathRepr::PathBuf(v)) 61 VfsPath(VfsPathRepr::PathBuf(v.normalize()))
40 } 62 }
41} 63}
42 64
@@ -44,6 +66,33 @@ impl fmt::Display for VfsPath {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match &self.0 { 67 match &self.0 {
46 VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f), 68 VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f),
69 VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
75struct VirtualPath(String);
76
77impl VirtualPath {
78 fn starts_with(&self, other: &VirtualPath) -> bool {
79 self.0.starts_with(&other.0)
80 }
81 fn pop(&mut self) -> bool {
82 let pos = match self.0.rfind('/') {
83 Some(pos) => pos,
84 None => return false,
85 };
86 self.0 = self.0[..pos].to_string();
87 true
88 }
89 fn join(&self, mut path: &str) -> VirtualPath {
90 let mut res = self.clone();
91 while path.starts_with("../") {
92 assert!(res.pop());
93 path = &path["../".len()..]
47 } 94 }
95 res.0 = format!("{}/{}", res.0, path);
96 res
48 } 97 }
49} 98}
diff --git a/crates/vfs/src/walkdir_loader.rs b/crates/vfs/src/walkdir_loader.rs
deleted file mode 100644
index 13e59e3f3..000000000
--- a/crates/vfs/src/walkdir_loader.rs
+++ /dev/null
@@ -1,108 +0,0 @@
1//! A walkdir-based implementation of `loader::Handle`, which doesn't try to
2//! watch files.
3use std::convert::TryFrom;
4
5use globset::{Glob, GlobSetBuilder};
6use paths::{AbsPath, AbsPathBuf};
7use walkdir::WalkDir;
8
9use crate::loader;
10
11#[derive(Debug)]
12pub struct WalkdirLoaderHandle {
13 // Relative order of fields below is significant.
14 sender: crossbeam_channel::Sender<Message>,
15 _thread: jod_thread::JoinHandle,
16}
17
18enum Message {
19 Config(loader::Config),
20 Invalidate(AbsPathBuf),
21}
22
23impl loader::Handle for WalkdirLoaderHandle {
24 fn spawn(sender: loader::Sender) -> WalkdirLoaderHandle {
25 let actor = WalkdirLoaderActor { sender };
26 let (sender, receiver) = crossbeam_channel::unbounded::<Message>();
27 let thread = jod_thread::spawn(move || actor.run(receiver));
28 WalkdirLoaderHandle { sender, _thread: thread }
29 }
30 fn set_config(&mut self, config: loader::Config) {
31 self.sender.send(Message::Config(config)).unwrap()
32 }
33 fn invalidate(&mut self, path: AbsPathBuf) {
34 self.sender.send(Message::Invalidate(path)).unwrap();
35 }
36 fn load_sync(&mut self, path: &AbsPathBuf) -> Option<Vec<u8>> {
37 read(path)
38 }
39}
40
41struct WalkdirLoaderActor {
42 sender: loader::Sender,
43}
44
45impl WalkdirLoaderActor {
46 fn run(mut self, receiver: crossbeam_channel::Receiver<Message>) {
47 for msg in receiver {
48 match msg {
49 Message::Config(config) => {
50 self.send(loader::Message::DidSwitchConfig { n_entries: config.load.len() });
51 for entry in config.load.into_iter() {
52 let files = self.load_entry(entry);
53 self.send(loader::Message::Loaded { files });
54 }
55 drop(config.watch);
56 self.send(loader::Message::DidLoadAllEntries);
57 }
58 Message::Invalidate(path) => {
59 let contents = read(path.as_path());
60 let files = vec![(path, contents)];
61 self.send(loader::Message::Loaded { files });
62 }
63 }
64 }
65 }
66 fn load_entry(&mut self, entry: loader::Entry) -> Vec<(AbsPathBuf, Option<Vec<u8>>)> {
67 match entry {
68 loader::Entry::Files(files) => files
69 .into_iter()
70 .map(|file| {
71 let contents = read(file.as_path());
72 (file, contents)
73 })
74 .collect::<Vec<_>>(),
75 loader::Entry::Directory { path, globs } => {
76 let globset = {
77 let mut builder = GlobSetBuilder::new();
78 for glob in &globs {
79 builder.add(Glob::new(glob).unwrap());
80 }
81 builder.build().unwrap()
82 };
83
84 let files = WalkDir::new(path)
85 .into_iter()
86 .filter_map(|it| it.ok())
87 .filter(|it| it.file_type().is_file())
88 .map(|it| it.into_path())
89 .map(|it| AbsPathBuf::try_from(it).unwrap())
90 .filter(|it| globset.is_match(&it));
91
92 files
93 .map(|file| {
94 let contents = read(file.as_path());
95 (file, contents)
96 })
97 .collect()
98 }
99 }
100 }
101 fn send(&mut self, msg: loader::Message) {
102 (self.sender)(msg)
103 }
104}
105
106fn read(path: &AbsPath) -> Option<Vec<u8>> {
107 std::fs::read(path).ok()
108}