private static @NotNull <T> BackgroundTask<T> createBackgroundTask(@NotNull Executor executor,
                                                                     @NotNull Computable<? extends T> task,
                                                                     @NotNull @NlsSafe String taskName,
                                                                     @NotNull Disposable parent) {
    ProgressIndicator indicator = new EmptyProgressIndicator();

    AtomicReference<Future<?>> futureRef = new AtomicReference<>();
    Disposable disposable = () -> {
      if (indicator.isRunning()) {
        indicator.cancel();
      }

      Future<?> future = futureRef.get();
      if (future != null) {
        tryAwaitFuture(future, taskName); // give a task chance to finish in sync
      }
    };

    CompletableFuture<T> future = CompletableFuture.supplyAsync(() -> {
      return ProgressManager.getInstance().runProcess(() -> {
        if (!registerIfParentNotDisposed(parent, disposable)) {
          throw new ProcessCanceledException();
        }

        return task.compute();
      }, indicator);
    }, executor);
    future.whenComplete((o, e) -> Disposer.dispose(disposable));
    futureRef.set(future);

    return new BackgroundTask<>(parent, indicator, future);
  }
private static @NotNull <T> BackgroundTask<T> createBackgroundTask(@NotNull Executor executor,
                                                                     @NotNull Computable<? extends T> task,
                                                                     @NotNull @NlsSafe String taskName,
                                                                     @NotNull Disposable parent)