aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_vfs/Cargo.toml1
-rw-r--r--crates/ra_vfs/src/lib.rs4
-rw-r--r--crates/ra_vfs/src/watcher.rs57
3 files changed, 46 insertions, 16 deletions
diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml
index 1a21557bf..58196555c 100644
--- a/crates/ra_vfs/Cargo.toml
+++ b/crates/ra_vfs/Cargo.toml
@@ -12,6 +12,7 @@ crossbeam-channel = "0.3.5"
12log = "0.4.6" 12log = "0.4.6"
13# until https://github.com/passcod/notify/issues/169 is fixed 13# until https://github.com/passcod/notify/issues/169 is fixed
14notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" } 14notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" }
15ignore = "0.4"
15drop_bomb = "0.1.0" 16drop_bomb = "0.1.0"
16 17
17thread_worker = { path = "../thread_worker" } 18thread_worker = { path = "../thread_worker" }
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index 48a46d210..ad40db340 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -141,9 +141,7 @@ impl Vfs {
141 }; 141 };
142 res.worker.inp.send(task).unwrap(); 142 res.worker.inp.send(task).unwrap();
143 if let Some(ref mut watcher) = res.watcher { 143 if let Some(ref mut watcher) = res.watcher {
144 if let Err(e) = watcher.watch(path) { 144 watcher.watch(path);
145 log::warn!("could not watch \"{}\": {}", path.display(), e);
146 }
147 } 145 }
148 } 146 }
149 let roots = res.roots.iter().map(|(id, _)| id).collect(); 147 let roots = res.roots.iter().map(|(id, _)| id).collect();
diff --git a/crates/ra_vfs/src/watcher.rs b/crates/ra_vfs/src/watcher.rs
index dfbbcbfe6..013611e1a 100644
--- a/crates/ra_vfs/src/watcher.rs
+++ b/crates/ra_vfs/src/watcher.rs
@@ -1,17 +1,17 @@
1use crate::io;
2use crossbeam_channel::Sender;
3use drop_bomb::DropBomb;
4use ignore;
5use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher};
1use std::{ 6use std::{
2 path::{Path, PathBuf}, 7 path::{Path, PathBuf},
3 sync::mpsc, 8 sync::{mpsc, Arc, Mutex},
4 thread, 9 thread,
5 time::Duration, 10 time::Duration,
6}; 11};
7 12
8use crate::io;
9use crossbeam_channel::Sender;
10use drop_bomb::DropBomb;
11use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher};
12
13pub struct Watcher { 13pub struct Watcher {
14 watcher: RecommendedWatcher, 14 watcher: Arc<Mutex<RecommendedWatcher>>,
15 thread: thread::JoinHandle<()>, 15 thread: thread::JoinHandle<()>,
16 bomb: DropBomb, 16 bomb: DropBomb,
17} 17}
@@ -24,9 +24,10 @@ pub enum WatcherChange {
24 Rescan, 24 Rescan,
25} 25}
26 26
27fn send_change_events( 27fn handle_change_event(
28 ev: DebouncedEvent, 28 ev: DebouncedEvent,
29 sender: &Sender<io::Task>, 29 sender: &Sender<io::Task>,
30 watcher: &Arc<Mutex<RecommendedWatcher>>,
30) -> Result<(), Box<std::error::Error>> { 31) -> Result<(), Box<std::error::Error>> {
31 match ev { 32 match ev {
32 DebouncedEvent::NoticeWrite(_) 33 DebouncedEvent::NoticeWrite(_)
@@ -38,6 +39,9 @@ fn send_change_events(
38 sender.send(io::Task::HandleChange(WatcherChange::Rescan))?; 39 sender.send(io::Task::HandleChange(WatcherChange::Rescan))?;
39 } 40 }
40 DebouncedEvent::Create(path) => { 41 DebouncedEvent::Create(path) => {
42 if path.is_dir() {
43 watch_recursive(watcher, &path);
44 }
41 sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?; 45 sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?;
42 } 46 }
43 DebouncedEvent::Write(path) => { 47 DebouncedEvent::Write(path) => {
@@ -58,17 +62,45 @@ fn send_change_events(
58 Ok(()) 62 Ok(())
59} 63}
60 64
65fn watch_one(watcher: &mut RecommendedWatcher, path: &Path) {
66 match watcher.watch(path, RecursiveMode::NonRecursive) {
67 Ok(()) => log::debug!("watching \"{}\"", path.display()),
68 Err(e) => log::warn!("could not watch \"{}\": {}", path.display(), e),
69 }
70}
71
72fn watch_recursive(watcher: &Arc<Mutex<RecommendedWatcher>>, path: &Path) {
73 log::debug!("watch_recursive \"{}\"", path.display());
74 let mut w = watcher.lock().unwrap();
75 // TODO it seems path itself isn't checked against ignores
76 // check if path should be ignored before walking it
77 for res in ignore::Walk::new(path) {
78 match res {
79 Ok(entry) => {
80 if entry.path().is_dir() {
81 watch_one(&mut w, entry.path());
82 }
83 }
84 Err(e) => log::warn!("watcher error: {}", e),
85 }
86 }
87}
88
61impl Watcher { 89impl Watcher {
62 pub(crate) fn start( 90 pub(crate) fn start(
63 output_sender: Sender<io::Task>, 91 output_sender: Sender<io::Task>,
64 ) -> Result<Watcher, Box<std::error::Error>> { 92 ) -> Result<Watcher, Box<std::error::Error>> {
65 let (input_sender, input_receiver) = mpsc::channel(); 93 let (input_sender, input_receiver) = mpsc::channel();
66 let watcher = notify::watcher(input_sender, Duration::from_millis(250))?; 94 let watcher = Arc::new(Mutex::new(notify::watcher(
95 input_sender,
96 Duration::from_millis(250),
97 )?));
98 let w = watcher.clone();
67 let thread = thread::spawn(move || { 99 let thread = thread::spawn(move || {
68 input_receiver 100 input_receiver
69 .into_iter() 101 .into_iter()
70 // forward relevant events only 102 // forward relevant events only
71 .try_for_each(|change| send_change_events(change, &output_sender)) 103 .try_for_each(|change| handle_change_event(change, &output_sender, &w))
72 .unwrap() 104 .unwrap()
73 }); 105 });
74 Ok(Watcher { 106 Ok(Watcher {
@@ -78,9 +110,8 @@ impl Watcher {
78 }) 110 })
79 } 111 }
80 112
81 pub fn watch(&mut self, root: impl AsRef<Path>) -> Result<(), Box<std::error::Error>> { 113 pub fn watch(&mut self, root: impl AsRef<Path>) {
82 self.watcher.watch(root, RecursiveMode::Recursive)?; 114 watch_recursive(&self.watcher, root.as_ref());
83 Ok(())
84 } 115 }
85 116
86 pub fn shutdown(mut self) -> thread::Result<()> { 117 pub fn shutdown(mut self) -> thread::Result<()> {