CompletableFuture<ProgressResult<R>> () { /* General flow: 1. Create Progress 2. (opt) Get on write thread to grab modality 3. Grab modality 4. (opt) Release IW 5. Run/Launch task 6. (opt) Poll tasks on WT */ boolean forceSyncExec = checkIfForceDirectExecNeeded(); CompletableFuture<? extends @NotNull ProgressIndicator> progressFuture = myProgressIndicatorFuture.thenApply(progress -> { // in case of abrupt application exit when 'ProgressManager.getInstance().runProcess(process, progress)' below // does not have a chance to run, and as a result the progress won't be disposed if (progress instanceof Disposable) { Disposer.register(ApplicationManager.getApplication(), (Disposable)progress); } return progress; }); CompletableFuture<R> resultFuture; if (forceSyncExec) { resultFuture = new CompletableFuture<>(); try { ProgressIndicator progressIndicator = progressFuture.join(); resultFuture.complete(ProgressManager.getInstance().runProcess(() -> myComputation.apply(progressIndicator), progressIndicator)); } catch (Throwable t) { resultFuture.completeExceptionally(t); } } else { Semaphore modalityEntered = new Semaphore(1); Function<@NotNull ProgressIndicator, R> onThreadCallable = (progressIndicator) -> { if (isModal) { modalityEntered.waitFor(); } // runProcess handles starting/stopping progress and setting thread's current progress return ProgressManager.getInstance().runProcess(() -> myComputation.apply(progressIndicator), progressIndicator); }; if (ApplicationManager.getApplication().isDispatchThread()) { resultFuture = execFromEDT(progressFuture, modalityEntered, onThreadCallable); } else { resultFuture = normalExec(progressFuture, modalityEntered, onThreadCallable); } } return resultFuture.handle((result, e) -> { Throwable throwable = unwrap(e); if (LOG.isDebugEnabled()) { if (throwable != null) { LOG.debug("ProgressRunner: task completed with throwable", throwable); } if (isCanceled(progressFuture)) { LOG.debug("ProgressRunner: task cancelled"); } } return new ProgressResult<>(result, throwable instanceof ProcessCanceledException || isCanceled(progressFuture), throwable); }); }