diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ExtractDeclarationFromCurrentFileIntention.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ExtractDeclarationFromCurrentFileIntention.kt index c2fc1e870c5..ffe4e0266b6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ExtractDeclarationFromCurrentFileIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ExtractDeclarationFromCurrentFileIntention.kt @@ -11,7 +11,10 @@ import com.intellij.codeInsight.navigation.NavigationUtil import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiDirectory +import com.intellij.psi.PsiFile import com.intellij.refactoring.move.MoveCallback import com.intellij.refactoring.util.CommonRefactoringUtil import kotlinx.coroutines.runBlocking @@ -22,7 +25,9 @@ import org.jetbrains.kotlin.idea.core.moveCaret import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention import org.jetbrains.kotlin.idea.refactoring.createKotlinFile import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog +import org.jetbrains.kotlin.idea.refactoring.showWithTransaction import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.isAncestor @@ -47,11 +52,10 @@ class ExtractDeclarationFromCurrentFileIntention : } override fun applicabilityRange(element: KtClassOrObject): TextRange? { - if (element.name == null) return null + element.name ?: return null if (element.parent !is KtFile) return null if (element.hasModifier(KtTokens.PRIVATE_KEYWORD)) return null - if (element.containingKtFile.declarations.size == 1) return null - + if (element.containingKtFile.run { declarations.size == 1 || containingDirectory === null }) return null val extraClassesToMove = element.tryGetExtraClassesToMove() ?: return null val startOffset = when (element) { @@ -71,7 +75,7 @@ class ExtractDeclarationFromCurrentFileIntention : override fun startInWriteAction() = false override fun applyTo(element: KtClassOrObject, editor: Editor?) { - if (editor == null) throw IllegalArgumentException("This intention requires an editor") + requireNotNull(editor) { "This intention requires an editor" } val file = element.containingKtFile val project = file.project val originalOffset = editor.caretModel.offset - element.startOffset @@ -79,38 +83,17 @@ class ExtractDeclarationFromCurrentFileIntention : val packageName = file.packageFqName val targetFileName = "${element.name}.kt" val targetFile = directory.findFile(targetFileName) - if (targetFile != null) { + + if (targetFile !== null) { if (ApplicationManager.getApplication().isUnitTestMode) { throw CommonRefactoringUtil.RefactoringErrorHintException("File $targetFileName already exists") } - // If automatic move is not possible, fall back to full-fledged Move Declarations refactoring - ApplicationManager.getApplication().invokeLater { - MoveKotlinTopLevelDeclarationsDialog( - project, - setOf(element), - packageName.asString(), - directory, - targetFile as? KtFile, - true, - true, - true, - true, - MoveCallback { - runBlocking { - withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { - OptimizeImportsProcessor( - project, - file - ).run() - } - } - } - ).show() - } + runFullFledgedMoveRefactoring(project, element, packageName, directory, targetFile, file) return } - val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, null) { + + val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, targetFile = null) { createKotlinFile(targetFileName, directory, packageName.asString()) } @@ -120,22 +103,57 @@ class ExtractDeclarationFromCurrentFileIntention : } ?: MoveSource(element) + val moveCallBack = MoveCallback { + val newFile = directory.findFile(targetFileName) as KtFile + val newDeclaration = newFile.declarations.first() + NavigationUtil.activateFileWithPsiElement(newFile) + FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset) + runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } } + } + val descriptor = MoveDeclarationsDescriptor( - project = project, - moveSource = moveSource, - moveTarget = moveTarget, - delegate = MoveDeclarationsDelegate.TopLevel, + project, + moveSource, + moveTarget, + MoveDeclarationsDelegate.TopLevel, searchInCommentsAndStrings = false, searchInNonCode = false, - moveCallback = MoveCallback { - val newFile = directory.findFile(targetFileName) as KtFile - val newDeclaration = newFile.declarations.first() - NavigationUtil.activateFileWithPsiElement(newFile) - FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset) - runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } } - } + moveCallback = moveCallBack ) MoveKotlinDeclarationsProcessor(descriptor).run() } + + private fun runFullFledgedMoveRefactoring( + project: Project, + element: KtClassOrObject, + packageName: FqName, + directory: PsiDirectory, + targetFile: PsiFile?, + file: KtFile + ) { + ApplicationManager.getApplication().invokeLater { + + val callBack = MoveCallback { + runBlocking { + withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { + OptimizeImportsProcessor(project, file).run() + } + } + } + + MoveKotlinTopLevelDeclarationsDialog( + project, + setOf(element), + packageName.asString(), + directory, + targetFile as? KtFile, + /* moveToPackage = */ true, + /* searchInComments = */ true, + /* searchForTextOccurrences = */ true, + /* deleteEmptySourceFiles = */ true, + callBack + ).showWithTransaction() + } + } } \ No newline at end of file