private void updateLaterImpl(@NotNull ProgressIndicator indicator, boolean onlyEnabled) {
    List<DuplicateNode> allNodes = myTree.getModel().getAllDuplicates();
    List<? extends DuplicateNode> selectedNodes = onlyEnabled ? myTree.getModel().getEnabledDuplicates() : allNodes;
    IncrementalProgress progress = new IncrementalProgress(indicator, selectedNodes.size() + 4);

    PsiElement[] pattern = ReadAction.compute(() -> getPatternElements());
    PsiElement[] patternCopy = ReadAction.compute(() -> {
      PsiFile patternFile = pattern[0].getContainingFile();
      return IntroduceParameterHandler.getElementsInCopy(myProject, patternFile, pattern, false);
    });
    progress.increment(); // +1

    ExtractMethodSnapshot copySnapshot = ReadAction.compute(() -> new ExtractMethodSnapshot(mySnapshot, pattern, patternCopy));

    ExtractMethodProcessor copyProcessor = ReadAction.compute(() -> {
      JavaDuplicatesExtractMethodProcessor processor = new JavaDuplicatesExtractMethodProcessor(patternCopy,
                                                                                                ExtractMethodHandler.getRefactoringName());
      return processor.prepareFromSnapshot(copySnapshot, true) ? processor : null;
    });
    if (copyProcessor == null) return;

    Map<DuplicateNode, Match> duplicateMatches = ReadAction.compute(() -> findSelectedDuplicates(copyProcessor, selectedNodes));

    List<Duplicate> excludedDuplicates =
      onlyEnabled && allNodes.size() != duplicateMatches.size()
      ? ReadAction.compute(() -> collectExcludedRanges(allNodes, duplicateMatches.keySet(), patternCopy[0].getContainingFile()))
      : Collections.emptyList();

    ElementsRange patternReplacement = ReadAction.compute(() -> {
      Bounds bounds = new Bounds(patternCopy[0], patternCopy[patternCopy.length - 1]);
      copyProcessor.doExtract();
      return bounds.getElementsRange();
    });
    progress.increment(); // +2

    ReadAction.run(() -> copyProcessor.initParametrizedDuplicates(false));
    progress.increment(); // +3

    List<Duplicate> duplicateReplacements = new ArrayList<>();
    for (Map.Entry<DuplicateNode, Match> entry : duplicateMatches.entrySet()) {
      DuplicateNode duplicateNode = entry.getKey();
      Match duplicate = entry.getValue();

      ReadAction.run(() -> {
        Bounds bounds = new Bounds(duplicate.getMatchStart(), duplicate.getMatchEnd());
        copyProcessor.processMatch(duplicate);
        ElementsRange replacement = bounds.getElementsRange();
        duplicateReplacements.add(new Duplicate(duplicateNode, replacement));
      });
      progress.increment(); // +size()
    }

    PsiMethod method = ReadAction.compute(() -> {
      PsiMethod extractedMethod = copyProcessor.getExtractedMethod();
      return (PsiMethod)CodeStyleManager.getInstance(myProject).reformat(extractedMethod);
    });

    Document refactoredDocument = ReadAction.compute(() -> {
      PsiFile refactoredFile = method.getContainingFile();
      if (refactoredFile != null) {
        VirtualFile vFile = refactoredFile.getViewProvider().getVirtualFile();
        vFile.putUserData(DiffUtil.TEMP_FILE_KEY, Boolean.TRUE); // prevent Go To action to non-physical file
        return FileDocumentManager.getInstance().getDocument(vFile);
      }
      return null;
    });
    progress.increment(); // +4

    if (refactoredDocument != null) {
      ApplicationManager.getApplication().invokeLater(() -> {
        PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
        documentManager.doPostponedOperationsAndUnblockDocument(refactoredDocument);
        MethodNode methodNode = myTree.getModel().updateMethod(method);

        initDiff(pattern, patternReplacement, refactoredDocument,
                 methodNode, method.getTextRange(),
                 duplicateReplacements, excludedDuplicates);

        myTree.onUpdateLater();
      });
    }
  }
private void updateLaterImpl(@NotNull ProgressIndicator indicator, boolean onlyEnabled)