task<T> method

Future<T> task<T>(
  1. String description,
  2. Future<T> work()
)

Runs work while showing a spinner. The future's value is returned; thrown errors propagate to the caller after the terminal is restored.

Implementation

Future<T> task<T>(
  String description,
  Future<T> Function() work,
) async {
  T? result;
  Object? caughtError;
  StackTrace? caughtStack;
  final key = Key.symbol(#__inline_task);

  await runTerminal<Object?>(
    initialState: null,
    theme: _theme,
    terminal: _terminal(),
    mode: const RenderMode.flow(height: 1, autoGrow: true),
    allowNonInteractive: _allowNonInteractive,
    enableMouse: false,
    onEvent: (_, event, handle) {
      if (event is AsyncResolvedEvent && event.key == key) {
        handle.stop();
      }
    },
    render: (ctx, _) {
      ctx.draw(
        Async<T>(
          key: key,
          future: () async {
            try {
              final v = await work();
              result = v;
              return v;
            } catch (e, st) {
              caughtError = e;
              caughtStack = st;
              rethrow;
            }
          },
          onLoading: () => Spinner(label: description),
          onSuccess: (_) => Text(
            '✓ $description',
            style: Style(fg: ctx.theme.colors.success, bold: true),
          ),
          onError: (e, _) => Text(
            '✗ $description: $e',
            style: Style(fg: ctx.theme.colors.error, bold: true),
          ),
        ),
        Rect(ctx.area.x, ctx.area.y, ctx.area.width, 1),
      );
    },
  );

  if (caughtError != null) {
    Error.throwWithStackTrace(
        caughtError!, caughtStack ?? StackTrace.current);
  }
  return result as T;
}