aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_vfs/src/io.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_vfs/src/io.rs')
-rw-r--r--crates/ra_vfs/src/io.rs131
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 @@
1use std::{ 1use std::{fs, sync::Arc, thread};
2 fmt,
3 fs,
4 path::{Path, PathBuf},
5};
6 2
7use walkdir::{DirEntry, WalkDir}; 3use crossbeam_channel::{Receiver, Sender};
8use thread_worker::{WorkerHandle};
9use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use thread_worker::WorkerHandle;
6use walkdir::WalkDir;
10 7
11use crate::{VfsRoot, has_rs_extension}; 8mod watcher;
9use watcher::Watcher;
12 10
13pub(crate) struct Task { 11use crate::{RootFilter, Roots, VfsRoot};
14 pub(crate) root: VfsRoot, 12
15 pub(crate) path: PathBuf, 13pub(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
19pub struct TaskResult { 20#[derive(Debug)]
20 pub(crate) root: VfsRoot, 21pub 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
24impl fmt::Debug for TaskResult { 42pub(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
30pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>; 47impl 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
32pub(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
42fn handle_task(task: Task) -> TaskResult { 87fn 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
50fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> { 101fn 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