waitForChange method

Future<({String? file, EventType type})> waitForChange({
  1. required Iterable<String> testDirs,
  2. required Iterable<String> libDirs,
  3. required void printMessage(),
})

Implementation

Future<
    ({
      EventType type,
      String? file,
    })> waitForChange({
  required Iterable<String> testDirs,
  required Iterable<String> libDirs,
  required void Function() printMessage,
}) async {
  String eventType(int event) {
    switch (event) {
      case FileSystemEvent.create:
        return 'create';
      case FileSystemEvent.delete:
        return 'delete';
      case FileSystemEvent.move:
        return 'move';
      case FileSystemEvent.modify:
        return 'modify';
      case FileSystemEvent.all:
        return 'all';
      default:
        return 'unknown';
    }
  }

  final fileModifications = [...testDirs, ...libDirs].map((dir) {
    StreamSubscription<void>? subscription;
    final controller = StreamController<String>.broadcast(
      onCancel: () async {
        await subscription?.cancel();
      },
    );

    final watcher = fs.directory(dir).watch(recursive: true);

    subscription = watcher.listen((event) {
      logger
        ..detail('\n')
        ..detail('File event: ${eventType(event.type)}')
        ..detail('File changed: ${event.path}');

      controller.add(event.path);
    });

    return controller.stream;
  }).toList();

  final fileChangeCompleter = Completer<
      ({
        EventType type,
        String? file,
      })>();

  final input = keyPressListener.listenToKeystrokes(
    onExit: () {
      fileChangeCompleter.complete(
        (
          type: EventType.exit,
          file: null,
        ),
      );
    },
    onEscape: printMessage,
    customStrokes: {
      'r': () {
        fileChangeCompleter.complete(
          (
            type: EventType.run,
            file: null,
          ),
        );
      },
      't': () {
        fileChangeCompleter.complete(
          (
            type: EventType.toggleModified,
            file: null,
          ),
        );
      },
      'c': () {
        fileChangeCompleter.complete(
          (
            type: EventType.toggleConcurrency,
            file: null,
          ),
        );
      },
    },
  );

  StreamSubscription<void>? inputSubscription;
  inputSubscription = input?.listen((_) {});

  final fileChangeListener = StreamGroup(fileModifications).merge().listen(
        (file) => fileChangeCompleter.complete(
          (
            type: EventType.file,
            file: file,
          ),
        ),
      );

  final result = await fileChangeCompleter.future;
  await fileChangeListener.cancel();
  await inputSubscription?.cancel();

  return result;
}