From f181e36a44d1998d3239f09365b16bfea50288a4 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Sat, 19 Jan 2019 00:53:06 +0100 Subject: handle recursive watching ourselves --- crates/ra_vfs/Cargo.toml | 1 + crates/ra_vfs/src/lib.rs | 4 +--- crates/ra_vfs/src/watcher.rs | 57 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 16 deletions(-) (limited to 'crates/ra_vfs') 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" log = "0.4.6" # until https://github.com/passcod/notify/issues/169 is fixed notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" } +ignore = "0.4" drop_bomb = "0.1.0" thread_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 { }; res.worker.inp.send(task).unwrap(); if let Some(ref mut watcher) = res.watcher { - if let Err(e) = watcher.watch(path) { - log::warn!("could not watch \"{}\": {}", path.display(), e); - } + watcher.watch(path); } } 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 @@ +use crate::io; +use crossbeam_channel::Sender; +use drop_bomb::DropBomb; +use ignore; +use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; use std::{ path::{Path, PathBuf}, - sync::mpsc, + sync::{mpsc, Arc, Mutex}, thread, time::Duration, }; -use crate::io; -use crossbeam_channel::Sender; -use drop_bomb::DropBomb; -use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; - pub struct Watcher { - watcher: RecommendedWatcher, + watcher: Arc>, thread: thread::JoinHandle<()>, bomb: DropBomb, } @@ -24,9 +24,10 @@ pub enum WatcherChange { Rescan, } -fn send_change_events( +fn handle_change_event( ev: DebouncedEvent, sender: &Sender, + watcher: &Arc>, ) -> Result<(), Box> { match ev { DebouncedEvent::NoticeWrite(_) @@ -38,6 +39,9 @@ fn send_change_events( sender.send(io::Task::HandleChange(WatcherChange::Rescan))?; } DebouncedEvent::Create(path) => { + if path.is_dir() { + watch_recursive(watcher, &path); + } sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?; } DebouncedEvent::Write(path) => { @@ -58,17 +62,45 @@ fn send_change_events( Ok(()) } +fn watch_one(watcher: &mut RecommendedWatcher, path: &Path) { + match watcher.watch(path, RecursiveMode::NonRecursive) { + Ok(()) => log::debug!("watching \"{}\"", path.display()), + Err(e) => log::warn!("could not watch \"{}\": {}", path.display(), e), + } +} + +fn watch_recursive(watcher: &Arc>, path: &Path) { + log::debug!("watch_recursive \"{}\"", path.display()); + let mut w = watcher.lock().unwrap(); + // TODO it seems path itself isn't checked against ignores + // check if path should be ignored before walking it + for res in ignore::Walk::new(path) { + match res { + Ok(entry) => { + if entry.path().is_dir() { + watch_one(&mut w, entry.path()); + } + } + Err(e) => log::warn!("watcher error: {}", e), + } + } +} + impl Watcher { pub(crate) fn start( output_sender: Sender, ) -> Result> { let (input_sender, input_receiver) = mpsc::channel(); - let watcher = notify::watcher(input_sender, Duration::from_millis(250))?; + let watcher = Arc::new(Mutex::new(notify::watcher( + input_sender, + Duration::from_millis(250), + )?)); + let w = watcher.clone(); let thread = thread::spawn(move || { input_receiver .into_iter() // forward relevant events only - .try_for_each(|change| send_change_events(change, &output_sender)) + .try_for_each(|change| handle_change_event(change, &output_sender, &w)) .unwrap() }); Ok(Watcher { @@ -78,9 +110,8 @@ impl Watcher { }) } - pub fn watch(&mut self, root: impl AsRef) -> Result<(), Box> { - self.watcher.watch(root, RecursiveMode::Recursive)?; - Ok(()) + pub fn watch(&mut self, root: impl AsRef) { + watch_recursive(&self.watcher, root.as_ref()); } pub fn shutdown(mut self) -> thread::Result<()> { -- cgit v1.2.3