@@ -64,6 +64,7 @@ object Watching {
6464 var prevState : Option [T ] = None
6565 var enterKeyPressed = false
6666
67+ // Exits when the thread gets interruped.
6768 while (true ) {
6869 val Result (watchables, errorOpt, result) = evaluate(enterKeyPressed, prevState)
6970 prevState = Some (result)
@@ -74,10 +75,10 @@ object Watching {
7475 if (alreadyStale) {
7576 enterKeyPressed = false
7677 } else {
77- enterKeyPressed = watchAndWait(streams, watchArgs.setIdle, streams.in, watchables, watchArgs.colors)
78+ enterKeyPressed =
79+ watchAndWait(streams, watchArgs.setIdle, streams.in, watchables, watchArgs.colors)
7880 }
7981 }
80- // QUESTION: this never exits?
8182 throw new IllegalStateException (" unreachable" )
8283 }
8384 }
@@ -90,28 +91,46 @@ object Watching {
9091 colors : Colors
9192 ): Boolean = {
9293 setIdle(true )
93- val (watchedPollables, watchedPaths ) = watched.partitionMap {
94+ val (watchedPollables, watchedPathsSeq ) = watched.partitionMap {
9495 case w : Watchable .Pollable => Left (w)
9596 case p : Watchable .Path => Right (p)
9697 }
97- val watchedValueCount = watched.size - watchedPaths.size
98+ val watchedPathsSet = watchedPathsSeq.iterator.map(p => os.Path (p.p)).toSet
99+ val watchedValueCount = watched.size - watchedPathsSeq.size
98100
99101 val watchedValueStr =
100102 if (watchedValueCount == 0 ) " " else s " and $watchedValueCount other values "
101103
102104 streams.err.println(
103105 colors.info(
104- s " Watching for changes to ${watchedPaths .size} paths $watchedValueStr... (Enter to re-run, Ctrl-C to exit) "
106+ s " Watching for changes to ${watchedPathsSeq .size} paths $watchedValueStr... (Enter to re-run, Ctrl-C to exit) "
105107 ).toString
106108 )
107109
108110 @ volatile var pathChangesDetected = false
111+
112+ // oslib watch only works with folders, so we have to watch the parent folders instead
113+ val osLibWatchPaths = watchedPathsSet.iterator.map(p => p / " .." ).toSet
114+ // mill.constants.DebugLog(
115+ // colors.info(s"[watch:watched-paths] ${osLibWatchPaths.mkString("\n")}").toString
116+ // )
117+
109118 Using .resource(os.watch.watch(
110- watchedPaths.map(path => os.Path (path.p)),
111- onEvent = _ => pathChangesDetected = true ,
112- logger = (eventType, data) => {
113- streams.out.println(colors.info(s " [watch] $eventType: ${pprint.apply(data)}" ))
114- }
119+ osLibWatchPaths.toSeq,
120+ onEvent = changedPaths => {
121+ // Make sure that the changed paths are actually the ones in our watch list and not some adjacent files in the
122+ // same folder
123+ val hasWatchedPath = changedPaths.exists(p => watchedPathsSet.contains(p))
124+ // mill.constants.DebugLog(colors.info(
125+ // s"[watch:changed-paths] (hasWatchedPath=$hasWatchedPath) ${changedPaths.mkString("\n")}"
126+ // ).toString)
127+ if (hasWatchedPath) {
128+ pathChangesDetected = true
129+ }
130+ },
131+ // logger = (eventType, data) => {
132+ // mill.constants.DebugLog(colors.info(s"[watch] $eventType: ${pprint.apply(data)}").toString)
133+ // }
115134 )) { _ =>
116135 val enterKeyPressed =
117136 statWatchWait(watchedPollables, stdin, notifiablesChanged = () => pathChangesDetected)
0 commit comments