@@ -14,9 +14,11 @@ use futures_timer::Delay;
1414use notify:: event:: ModifyKind ;
1515use notify:: { Config , Error , Event , EventKind , RecommendedWatcher , RecursiveMode , Watcher } ;
1616use std:: collections:: HashMap ;
17+ use std:: io:: { IsTerminal , Read } ;
1718use std:: path:: { Path , PathBuf } ;
1819use std:: sync:: Arc ;
1920use std:: sync:: Mutex ;
21+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
2022use std:: time:: { Duration , Instant , SystemTime } ;
2123
2224#[ derive( Debug , Clone , PartialEq , Eq , Copy ) ]
@@ -208,6 +210,19 @@ async fn async_watch(
208210 } )
209211 . expect ( "Error setting Ctrl-C handler" ) ;
210212
213+ // When stdin is a pipe (not a TTY), monitor it for EOF so that the
214+ // parent process can signal a graceful shutdown by closing stdin.
215+ let stdin_closed = Arc :: new ( AtomicBool :: new ( false ) ) ;
216+ let stdin_closed_clone = Arc :: clone ( & stdin_closed) ;
217+ if !std:: io:: stdin ( ) . is_terminal ( ) {
218+ std:: thread:: spawn ( move || {
219+ let mut buf = [ 0u8 ; 1 ] ;
220+ // This blocks until EOF (Ok(0)) or an error occurs.
221+ let _ = std:: io:: stdin ( ) . read ( & mut buf) ;
222+ stdin_closed. store ( true , Ordering :: Relaxed ) ;
223+ } ) ;
224+ }
225+
211226 let mut initial_build = true ;
212227
213228 // Track file mtimes to deduplicate events.
@@ -217,7 +232,7 @@ async fn async_watch(
217232 let mut last_mtime: HashMap < PathBuf , SystemTime > = HashMap :: new ( ) ;
218233
219234 loop {
220- if * ctrlc_pressed_clone. lock ( ) . unwrap ( ) {
235+ if * ctrlc_pressed_clone. lock ( ) . unwrap ( ) || stdin_closed_clone . load ( Ordering :: Relaxed ) {
221236 if show_progress {
222237 println ! ( "\n Exiting..." ) ;
223238 }
0 commit comments