waitForChange method

Future<({bool exit})> waitForChange()

Implementation

Future<({bool exit})> waitForChange() async {
  final (configPath, exitCode) = await getConfigPath();
  if (exitCode != null) {
    return (exit: true);
  } else if (configPath == null) {
    return (exit: true);
  }

  final settings = await getSettings(configPath);

  final barrels = await getBarrels(settings);

  final directories = barrels.map((e) => e.dirSettings.dirPath).toSet();

  final events = {
    FileSystemEvent.delete,
    FileSystemEvent.create,
    FileSystemEvent.move
  };

  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 barrelPaths = barrels.map((e) => e.barrelFile).toSet();

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

    final watcher =
        fs.directory(dir).watch(recursive: true, events: FileSystemEvent.all);

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

      if (!events.contains(event.type)) {
        return;
      }

      controller.add(null);
    });

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

  void writeWaitingMessage() {
    final waitingMessage = '''
${yellow.wrap('Waiting for changes...')}
${darkGray.wrap('Press `Ctrl+C` or `q` to exit')}
${darkGray.wrap('Press `r` to rebuild')}
''';

    logger.write(waitingMessage);
  }

  final fileChangeCompleter = Completer<({bool exit})?>();

  final input = keyPressListener?.listenToKeystrokes(
    onExit: () {
      fileChangeCompleter.complete((exit: true));
    },
    onRebuild: () {
      fileChangeCompleter.complete();
    },
    onEscape: writeWaitingMessage,
  );

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

  final fileChangeListener = StreamGroup(fileModifications)
      .merge()
      .listen((_) => fileChangeCompleter.complete());

  writeWaitingMessage();

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

  final shouldExit = result?.exit ?? false;

  if (shouldExit) {
    return (exit: true);
  }

  final changeMessage = '''
${yellow.wrap('Changes detected')}
''';

  logger.write(changeMessage);

  return (exit: false);
}