diff options
Diffstat (limited to 'crates/ra_vfs/src/io.rs')
-rw-r--r-- | crates/ra_vfs/src/io.rs | 131 |
1 files changed, 91 insertions, 40 deletions
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs index 80328ad18..7ca1e9835 100644 --- a/crates/ra_vfs/src/io.rs +++ b/crates/ra_vfs/src/io.rs | |||
@@ -1,55 +1,109 @@ | |||
1 | use std::{ | 1 | use std::{fs, sync::Arc, thread}; |
2 | fmt, | ||
3 | fs, | ||
4 | path::{Path, PathBuf}, | ||
5 | }; | ||
6 | 2 | ||
7 | use walkdir::{DirEntry, WalkDir}; | 3 | use crossbeam_channel::{Receiver, Sender}; |
8 | use thread_worker::{WorkerHandle}; | ||
9 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | use thread_worker::WorkerHandle; | ||
6 | use walkdir::WalkDir; | ||
10 | 7 | ||
11 | use crate::{VfsRoot, has_rs_extension}; | 8 | mod watcher; |
9 | use watcher::Watcher; | ||
12 | 10 | ||
13 | pub(crate) struct Task { | 11 | use crate::{RootFilter, Roots, VfsRoot}; |
14 | pub(crate) root: VfsRoot, | 12 | |
15 | pub(crate) path: PathBuf, | 13 | pub(crate) enum Task { |
16 | pub(crate) filter: Box<Fn(&DirEntry) -> bool + Send>, | 14 | AddRoot { |
15 | root: VfsRoot, | ||
16 | filter: Arc<RootFilter>, | ||
17 | }, | ||
17 | } | 18 | } |
18 | 19 | ||
19 | pub struct TaskResult { | 20 | #[derive(Debug)] |
20 | pub(crate) root: VfsRoot, | 21 | pub enum TaskResult { |
21 | pub(crate) files: Vec<(RelativePathBuf, String)>, | 22 | BulkLoadRoot { |
23 | root: VfsRoot, | ||
24 | files: Vec<(RelativePathBuf, String)>, | ||
25 | }, | ||
26 | AddSingleFile { | ||
27 | root: VfsRoot, | ||
28 | path: RelativePathBuf, | ||
29 | text: String, | ||
30 | }, | ||
31 | ChangeSingleFile { | ||
32 | root: VfsRoot, | ||
33 | path: RelativePathBuf, | ||
34 | text: String, | ||
35 | }, | ||
36 | RemoveSingleFile { | ||
37 | root: VfsRoot, | ||
38 | path: RelativePathBuf, | ||
39 | }, | ||
22 | } | 40 | } |
23 | 41 | ||
24 | impl fmt::Debug for TaskResult { | 42 | pub(crate) struct Worker { |
25 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 43 | worker: thread_worker::Worker<Task, TaskResult>, |
26 | f.write_str("TaskResult { ... }") | 44 | worker_handle: WorkerHandle, |
27 | } | ||
28 | } | 45 | } |
29 | 46 | ||
30 | pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>; | 47 | impl Worker { |
48 | pub(crate) fn start(roots: Arc<Roots>) -> Worker { | ||
49 | let (worker, worker_handle) = | ||
50 | thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| { | ||
51 | let mut watcher = match Watcher::start(roots, output_sender.clone()) { | ||
52 | Ok(w) => Some(w), | ||
53 | Err(e) => { | ||
54 | log::error!("could not start watcher: {}", e); | ||
55 | None | ||
56 | } | ||
57 | }; | ||
58 | let res = input_receiver | ||
59 | .into_iter() | ||
60 | .filter_map(|t| handle_task(t, &mut watcher)) | ||
61 | .try_for_each(|it| output_sender.send(it)); | ||
62 | if let Some(watcher) = watcher { | ||
63 | let _ = watcher.shutdown(); | ||
64 | } | ||
65 | res.unwrap() | ||
66 | }); | ||
67 | Worker { | ||
68 | worker, | ||
69 | worker_handle, | ||
70 | } | ||
71 | } | ||
72 | |||
73 | pub(crate) fn sender(&self) -> &Sender<Task> { | ||
74 | &self.worker.inp | ||
75 | } | ||
76 | |||
77 | pub(crate) fn receiver(&self) -> &Receiver<TaskResult> { | ||
78 | &self.worker.out | ||
79 | } | ||
31 | 80 | ||
32 | pub(crate) fn start() -> (Worker, WorkerHandle) { | 81 | pub(crate) fn shutdown(self) -> thread::Result<()> { |
33 | thread_worker::spawn("vfs", 128, |input_receiver, output_sender| { | 82 | let _ = self.worker.shutdown(); |
34 | input_receiver | 83 | self.worker_handle.shutdown() |
35 | .into_iter() | 84 | } |
36 | .map(handle_task) | ||
37 | .try_for_each(|it| output_sender.send(it)) | ||
38 | .unwrap() | ||
39 | }) | ||
40 | } | 85 | } |
41 | 86 | ||
42 | fn handle_task(task: Task) -> TaskResult { | 87 | fn handle_task(task: Task, watcher: &mut Option<Watcher>) -> Option<TaskResult> { |
43 | let Task { root, path, filter } = task; | 88 | match task { |
44 | log::debug!("loading {} ...", path.as_path().display()); | 89 | Task::AddRoot { root, filter } => { |
45 | let files = load_root(path.as_path(), &*filter); | 90 | if let Some(watcher) = watcher { |
46 | log::debug!("... loaded {}", path.as_path().display()); | 91 | watcher.watch_root(&filter) |
47 | TaskResult { root, files } | 92 | } |
93 | log::debug!("loading {} ...", filter.root.as_path().display()); | ||
94 | let files = load_root(filter.as_ref()); | ||
95 | log::debug!("... loaded {}", filter.root.as_path().display()); | ||
96 | Some(TaskResult::BulkLoadRoot { root, files }) | ||
97 | } | ||
98 | } | ||
48 | } | 99 | } |
49 | 100 | ||
50 | fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> { | 101 | fn load_root(filter: &RootFilter) -> Vec<(RelativePathBuf, String)> { |
51 | let mut res = Vec::new(); | 102 | let mut res = Vec::new(); |
52 | for entry in WalkDir::new(root).into_iter().filter_entry(filter) { | 103 | for entry in WalkDir::new(&filter.root) |
104 | .into_iter() | ||
105 | .filter_entry(filter.entry_filter()) | ||
106 | { | ||
53 | let entry = match entry { | 107 | let entry = match entry { |
54 | Ok(entry) => entry, | 108 | Ok(entry) => entry, |
55 | Err(e) => { | 109 | Err(e) => { |
@@ -61,9 +115,6 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa | |||
61 | continue; | 115 | continue; |
62 | } | 116 | } |
63 | let path = entry.path(); | 117 | let path = entry.path(); |
64 | if !has_rs_extension(path) { | ||
65 | continue; | ||
66 | } | ||
67 | let text = match fs::read_to_string(path) { | 118 | let text = match fs::read_to_string(path) { |
68 | Ok(text) => text, | 119 | Ok(text) => text, |
69 | Err(e) => { | 120 | Err(e) => { |
@@ -71,7 +122,7 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa | |||
71 | continue; | 122 | continue; |
72 | } | 123 | } |
73 | }; | 124 | }; |
74 | let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap(); | 125 | let path = RelativePathBuf::from_path(path.strip_prefix(&filter.root).unwrap()).unwrap(); |
75 | res.push((path.to_owned(), text)) | 126 | res.push((path.to_owned(), text)) |
76 | } | 127 | } |
77 | res | 128 | res |