watch method

Stream<FileEvent> watch(
  1. String path, {
  2. WatcherConfig config = const WatcherConfig(),
})

Starts watching path with the provided config.

Returns a broadcast Stream of FileEvents. Only one watcher per path is active at a time; calling watch again for the same path replaces the previous watcher.

Implementation

Stream<FileEvent> watch(
  String path, {
  WatcherConfig config = const WatcherConfig(),
}) {
  // Cancel existing watcher for this path.
  _subscriptions[path]?.cancel();

  final controller = StreamController<FileEvent>.broadcast();
  final compiledIgnore = config.ignorePatterns
      .map(GlobMatcher.compile)
      .toList();

  final entity = FileSystemEntity.isDirectorySync(path)
      ? Directory(path)
      : File(path);

  // Debounce tracking.
  final lastEmit = <String, DateTime>{};

  final sub = entity.watch(recursive: config.recursive).listen((fse) {
    final eventPath = normalizePath(fse.path);

    // Filter by extension.
    if (config.filters.isNotEmpty) {
      final ext = getExtension(eventPath);
      if (!config.filters.contains(ext)) return;
    }

    // Ignore hidden.
    if (config.ignoreHidden && isHidden(eventPath)) return;

    // Ignore patterns.
    for (final glob in compiledIgnore) {
      if (glob.match(eventPath)) return;
    }

    // Debounce.
    final now = DateTime.now();
    final last = lastEmit[eventPath];
    if (last != null && now.difference(last) < config.debounce) return;
    lastEmit[eventPath] = now;

    final type = switch (fse.type) {
      FileSystemEvent.create => FileEventType.create,
      FileSystemEvent.modify => FileEventType.modify,
      FileSystemEvent.delete => FileEventType.delete,
      FileSystemEvent.move => FileEventType.rename,
      _ => FileEventType.modify,
    };

    controller.add(FileEvent(type: type, path: eventPath, timestamp: now));
  });

  _subscriptions[path] = sub;

  // Clean up when the controller has no listeners.
  controller.onCancel = () {
    sub.cancel();
    _subscriptions.remove(path);
  };

  return controller.stream;
}