void (@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(); }); } }