@@ -34,6 +34,8 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
3434 final _readyCompleter = Completer <void >();
3535
3636 StreamSubscription <List <FileSystemEvent >>? _subscription;
37+ Future <bool >? _existedAtStartupFuture;
38+ bool ? _existedAtStartup;
3739
3840 _NativeFileWatcher (this .path) {
3941 _listen ();
@@ -44,20 +46,37 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
4446 }
4547
4648 void _listen () {
49+ var file = File (path);
50+
4751 // Batch the events together so that we can dedup them.
48- _subscription = File (path)
52+ _subscription = file
4953 .watch ()
5054 .batchEvents ()
5155 .listen (_onBatch, onError: _eventsController.addError, onDone: _onDone);
56+
57+ // On MacOS events can arrive from file changes before the `watch`. Check
58+ // existence on startup to differentiate creation before and after the
59+ // `watch`.
60+ if (Platform .isMacOS) _existedAtStartupFuture = file.exists ();
5261 }
5362
54- void _onBatch (List <FileSystemEvent > batch) {
63+ void _onBatch (List <FileSystemEvent > batch) async {
5564 if (batch.any ((event) => event.type == FileSystemEvent .delete)) {
5665 // If the file is deleted, the underlying stream will close. We handle
5766 // emitting our own REMOVE event in [_onDone].
5867 return ;
5968 }
6069
70+ if (Platform .isMacOS) {
71+ var existedAtStartup =
72+ _existedAtStartup ?? = await _existedAtStartupFuture! ;
73+ if (existedAtStartup &&
74+ batch.every ((event) => event.type == FileSystemEvent .create)) {
75+ // It's a create event from before `watch` was called, ignore it.
76+ return ;
77+ }
78+ }
79+
6180 _eventsController.add (WatchEvent (ChangeType .MODIFY , path));
6281 }
6382
0 commit comments