66//!
77//! Hopefully, one day a reliable file watching/walking crate appears on
88//! crates.io, and we can reduce this to trivial glue code.
9- mod include;
10-
11- use std:: convert:: { TryFrom , TryInto } ;
9+ use std:: convert:: TryFrom ;
1210
1311use crossbeam_channel:: { never, select, unbounded, Receiver , Sender } ;
1412use notify:: { RecommendedWatcher , RecursiveMode , Watcher } ;
1513use paths:: { AbsPath , AbsPathBuf } ;
1614use vfs:: loader;
1715use walkdir:: WalkDir ;
1816
19- use crate :: include:: Include ;
20-
2117#[ derive( Debug ) ]
2218pub struct NotifyHandle {
2319 // Relative order of fields below is significant.
@@ -53,7 +49,7 @@ type NotifyEvent = notify::Result<notify::Event>;
5349
5450struct NotifyActor {
5551 sender : loader:: Sender ,
56- config : Vec < ( AbsPathBuf , Include , bool ) > ,
52+ watched_entries : Vec < loader :: Entry > ,
5753 // Drop order is significant.
5854 watcher : Option < ( RecommendedWatcher , Receiver < NotifyEvent > ) > ,
5955}
@@ -66,7 +62,7 @@ enum Event {
6662
6763impl NotifyActor {
6864 fn new ( sender : loader:: Sender ) -> NotifyActor {
69- NotifyActor { sender, config : Vec :: new ( ) , watcher : None }
65+ NotifyActor { sender, watched_entries : Vec :: new ( ) , watcher : None }
7066 }
7167 fn next_event ( & self , receiver : & Receiver < Message > ) -> Option < Event > {
7268 let watcher_receiver = self . watcher . as_ref ( ) . map ( |( _, receiver) | receiver) ;
@@ -93,15 +89,17 @@ impl NotifyActor {
9389 let n_total = config. load . len ( ) ;
9490 self . send ( loader:: Message :: Progress { n_total, n_done : 0 } ) ;
9591
96- self . config . clear ( ) ;
92+ self . watched_entries . clear ( ) ;
9793
9894 for ( i, entry) in config. load . into_iter ( ) . enumerate ( ) {
9995 let watch = config. watch . contains ( & i) ;
96+ if watch {
97+ self . watched_entries . push ( entry. clone ( ) )
98+ }
10099 let files = self . load_entry ( entry, watch) ;
101100 self . send ( loader:: Message :: Loaded { files } ) ;
102101 self . send ( loader:: Message :: Progress { n_total, n_done : i + 1 } ) ;
103102 }
104- self . config . sort_by ( |x, y| x. 0 . cmp ( & y. 0 ) ) ;
105103 }
106104 Message :: Invalidate ( path) => {
107105 let contents = read ( path. as_path ( ) ) ;
@@ -116,34 +114,27 @@ impl NotifyActor {
116114 . into_iter ( )
117115 . map ( |path| AbsPathBuf :: try_from ( path) . unwrap ( ) )
118116 . filter_map ( |path| {
119- let is_dir = path. is_dir ( ) ;
120- let is_file = path. is_file ( ) ;
121-
122- let config_idx =
123- match self . config . binary_search_by ( |it| it. 0 . cmp ( & path) ) {
124- Ok ( it) => it,
125- Err ( it) => it. saturating_sub ( 1 ) ,
126- } ;
127- let include = self . config . get ( config_idx) . and_then ( |it| {
128- let rel_path = path. strip_prefix ( & it. 0 ) ?;
129- Some ( ( rel_path, & it. 1 ) )
130- } ) ;
131-
132- if let Some ( ( rel_path, include) ) = include {
133- if is_dir && include. exclude_dir ( & rel_path)
134- || is_file && !include. include_file ( & rel_path)
135- {
136- return None ;
137- }
117+ if path. is_dir ( )
118+ && self
119+ . watched_entries
120+ . iter ( )
121+ . any ( |entry| entry. contains_dir ( & path) )
122+ {
123+ self . watch ( path) ;
124+ return None ;
138125 }
139126
140- if is_dir {
141- self . watch ( path) ;
127+ if !path. is_file ( ) {
142128 return None ;
143129 }
144- if !is_file {
130+ if !self
131+ . watched_entries
132+ . iter ( )
133+ . any ( |entry| entry. contains_file ( & path) )
134+ {
145135 return None ;
146136 }
137+
147138 let contents = read ( & path) ;
148139 Some ( ( path, contents) )
149140 } )
@@ -170,43 +161,42 @@ impl NotifyActor {
170161 ( file, contents)
171162 } )
172163 . collect :: < Vec < _ > > ( ) ,
173- loader:: Entry :: Directory { path, include } => {
174- let include = Include :: new ( include) ;
175- self . config . push ( ( path. clone ( ) , include. clone ( ) , watch) ) ;
176-
177- let files = WalkDir :: new ( & path)
178- . into_iter ( )
179- . filter_entry ( |entry| {
180- let abs_path: & AbsPath = entry. path ( ) . try_into ( ) . unwrap ( ) ;
181- match abs_path. strip_prefix ( & path) {
182- Some ( rel_path) => {
183- !( entry. file_type ( ) . is_dir ( ) && include. exclude_dir ( rel_path) )
184- }
185- None => false ,
164+ loader:: Entry :: Directories ( dirs) => {
165+ let mut res = Vec :: new ( ) ;
166+
167+ for root in dirs. include . iter ( ) {
168+ let walkdir = WalkDir :: new ( root) . into_iter ( ) . filter_entry ( |entry| {
169+ if !entry. file_type ( ) . is_dir ( ) {
170+ return true ;
186171 }
187- } )
188- . filter_map ( |entry| entry. ok ( ) )
189- . filter_map ( |entry| {
172+ let path = AbsPath :: assert ( entry. path ( ) ) ;
173+ root == path
174+ || dirs. exclude . iter ( ) . chain ( & dirs. include ) . all ( |it| it != path)
175+ } ) ;
176+
177+ let files = walkdir. filter_map ( |it| it. ok ( ) ) . filter_map ( |entry| {
190178 let is_dir = entry. file_type ( ) . is_dir ( ) ;
191179 let is_file = entry. file_type ( ) . is_file ( ) ;
192- let abs_path = AbsPathBuf :: try_from ( entry. into_path ( ) ) . unwrap ( ) ;
180+ let abs_path = AbsPathBuf :: assert ( entry. into_path ( ) ) ;
193181 if is_dir && watch {
194182 self . watch ( abs_path. clone ( ) ) ;
195183 }
196- let rel_path = abs_path. strip_prefix ( & path) ?;
197- if is_file && include. include_file ( & rel_path) {
198- Some ( abs_path)
199- } else {
200- None
184+ if !is_file {
185+ return None ;
186+ }
187+ let ext = abs_path. extension ( ) . unwrap_or_default ( ) ;
188+ if dirs. extensions . iter ( ) . all ( |it| it. as_str ( ) != ext) {
189+ return None ;
201190 }
191+ Some ( abs_path)
202192 } ) ;
203193
204- files
205- . map ( |file| {
194+ res. extend ( files. map ( |file| {
206195 let contents = read ( file. as_path ( ) ) ;
207196 ( file, contents)
208- } )
209- . collect ( )
197+ } ) ) ;
198+ }
199+ res
210200 }
211201 }
212202 }
0 commit comments