@@ -35,6 +35,13 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
3535
3636 StreamSubscription <List <FileSystemEvent >>? _subscription;
3737
38+ // On MacOS events can arrive from file changes before the `watch`. Check
39+ // existence on startup to differentiate creation before and after the
40+ // `watch`.
41+ final bool _startupExistenceCheck = Platform .isMacOS;
42+ Future <bool >? _existedAtStartupFuture;
43+ bool ? _existedAtStartup;
44+
3845 _NativeFileWatcher (this .path) {
3946 _listen ();
4047
@@ -44,20 +51,34 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
4451 }
4552
4653 void _listen () {
54+ var file = File (path);
55+
4756 // Batch the events together so that we can dedup them.
48- _subscription = File (path)
57+ _subscription = file
4958 .watch ()
5059 .batchEvents ()
5160 .listen (_onBatch, onError: _eventsController.addError, onDone: _onDone);
61+
62+ if (_startupExistenceCheck) _existedAtStartupFuture = file.exists ();
5263 }
5364
54- void _onBatch (List <FileSystemEvent > batch) {
65+ void _onBatch (List <FileSystemEvent > batch) async {
5566 if (batch.any ((event) => event.type == FileSystemEvent .delete)) {
5667 // If the file is deleted, the underlying stream will close. We handle
5768 // emitting our own REMOVE event in [_onDone].
5869 return ;
5970 }
6071
72+ if (_startupExistenceCheck) {
73+ var existedAtStartup =
74+ _existedAtStartup ?? = await _existedAtStartupFuture! ;
75+ if (existedAtStartup &&
76+ batch.every ((event) => event.type == FileSystemEvent .create)) {
77+ // It's a create event from before `watch` was called, ignore it.
78+ return ;
79+ }
80+ }
81+
6182 _eventsController.add (WatchEvent (ChangeType .MODIFY , path));
6283 }
6384
0 commit comments