diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaExtractConstantFieldParameterVariableMethodCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaExtractConstantFieldParameterVariableMethodCompletionCommand.kt index c485385c014e..4713630b7be1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaExtractConstantFieldParameterVariableMethodCompletionCommand.kt +++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaExtractConstantFieldParameterVariableMethodCompletionCommand.kt @@ -7,6 +7,7 @@ import com.intellij.idea.ActionsBundle import com.intellij.openapi.editor.Editor import com.intellij.psi.* import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.elementType import com.intellij.psi.util.findParentOfType internal class JavaExtractConstantCompletionCommandProvider : AbstractExtractConstantCompletionCommandProvider() { @@ -44,6 +45,22 @@ internal class JavaExtractMethodCompletionCommandProvider : AbstractExtractMetho previewText = ActionsBundle.message("action.ExtractMethod.description"), synonyms = listOf("Extract method", "Introduce method") ) { + override fun findControlFlowStatement(offset: Int, psiFile: PsiFile): PsiStatement? { + val element = getCommandContext(offset, psiFile) ?: return null + val elementType = element.elementType + if (elementType != JavaTokenType.RBRACE && elementType != JavaTokenType.LBRACE) return null + + val parent = element.parent + if (parent !is PsiCodeBlock) return null + + val blockParent = parent.parent + if (blockParent !is PsiBlockStatement) return null + + val controlFlowStatement = blockParent.parent + if (controlFlowStatement is PsiLoopStatement || controlFlowStatement is PsiIfStatement) return controlFlowStatement + return null + } + override fun findOutermostExpression(offset: Int, psiFile: PsiFile, editor: Editor?): PsiElement? { val expression = findExpressionInsideMethod(offset, psiFile) if (expression?.findParentOfType() != null || expression?.findParentOfType() != null) return expression diff --git a/platform/lang-impl/api-dump-experimental.txt b/platform/lang-impl/api-dump-experimental.txt index f63995c87fbb..0d6109374be2 100644 --- a/platform/lang-impl/api-dump-experimental.txt +++ b/platform/lang-impl/api-dump-experimental.txt @@ -198,7 +198,9 @@ c:com.intellij.codeInsight.actions.VcsFacade - com.intellij.codeInsight.completion.command.commands.ActionCommandProvider - (java.lang.String,java.lang.String,java.lang.String,java.util.List):V - b:(java.lang.String,java.lang.String,java.lang.String,java.util.List,I,kotlin.jvm.internal.DefaultConstructorMarker):V -- a:findOutermostExpression(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):com.intellij.psi.PsiElement +- p:createCommand(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):com.intellij.codeInsight.completion.command.commands.ActionCompletionCommand +- pa:findControlFlowStatement(I,com.intellij.psi.PsiFile):com.intellij.psi.PsiElement +- pa:findOutermostExpression(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):com.intellij.psi.PsiElement - p:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z *a:com.intellij.codeInsight.completion.command.commands.AbstractExtractParameterCompletionCommandProvider - com.intellij.codeInsight.completion.command.commands.ActionCommandProvider diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractExtractConstantFieldParameterVariableMethodCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractExtractConstantFieldParameterVariableMethodCompletionCommand.kt index 1d0df83cf32d..4ef0d3d1ac7a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractExtractConstantFieldParameterVariableMethodCompletionCommand.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractExtractConstantFieldParameterVariableMethodCompletionCommand.kt @@ -101,9 +101,30 @@ abstract class AbstractExtractMethodCompletionCommandProvider( synonyms = synonyms, ) { override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean { - if (!super.isApplicable(offset, psiFile, editor)) return false - return findOutermostExpression(offset, psiFile, editor) != null + if (findControlFlowStatement(offset, psiFile) != null) return true + + return findOutermostExpression(offset, psiFile, editor) != null && super.isApplicable(offset, psiFile, editor) } - abstract fun findOutermostExpression(offset: Int, psiFile: PsiFile, editor: Editor?): PsiElement? + override fun createCommand(context: CommandCompletionProviderContext): ActionCompletionCommand { + return object : ActionCompletionCommand(actionId = super.actionId, + synonyms = super.synonyms, + presentableActionName = super.presentableName, + icon = super.icon, + priority = super.priority, + previewText = super.previewText) { + override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) { + if (editor == null) return + val controlFlowStatement = findControlFlowStatement(offset, psiFile) + if (controlFlowStatement != null) { + editor.selectionModel.setSelection(controlFlowStatement.textRange.startOffset, controlFlowStatement.textRange.endOffset) + } + super.execute(offset, psiFile, editor) + } + } + } + + protected abstract fun findOutermostExpression(offset: Int, psiFile: PsiFile, editor: Editor?): PsiElement? + + protected abstract fun findControlFlowStatement(offset: Int, psiFile: PsiFile): PsiElement? } diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/commands/KotlinExtractConstantFieldParameterVariableMethodCompletionCommand.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/commands/KotlinExtractConstantFieldParameterVariableMethodCompletionCommand.kt index b9f8e43917ed..991e623714fa 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/commands/KotlinExtractConstantFieldParameterVariableMethodCompletionCommand.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/commands/KotlinExtractConstantFieldParameterVariableMethodCompletionCommand.kt @@ -10,8 +10,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.elementType import com.intellij.psi.util.findParentOfType import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* internal class KotlinExtractParameterCompletionCommandProvider : AbstractExtractParameterCompletionCommandProvider() { @@ -39,6 +41,23 @@ internal class KotlinExtractMethodCompletionCommandProvider : AbstractExtractMet presentableName = KotlinBundle.message("action.ExtractFunction.text"), previewText = KotlinBundle.message("action.ExtractFunction.command.completion.description"), ) { + + override fun findControlFlowStatement(offset: Int, psiFile: PsiFile): PsiElement? { + val element = getCommandContext(offset, psiFile) ?: return null + val elementType = element.elementType + if (elementType != KtTokens.LBRACE && elementType != KtTokens.RBRACE) return null + + val parent = element.parent + if (parent !is KtBlockExpression) return null + + val containerNode = parent.parent + if (containerNode !is KtContainerNodeForControlStructureBody) return null + + val controlFlow = containerNode.parent + if (controlFlow is KtLoopExpression || controlFlow is KtIfExpression) return controlFlow + return null + } + override fun findOutermostExpression( offset: Int, psiFile: PsiFile,