[Java. Code completion] IDEA-379114 Basic support method command completion for blocks

GitOrigin-RevId: ac395901a6d9d2dc76571bb13dc10048dc885e1d
This commit is contained in:
Georgii Ustinov
2025-09-11 17:15:37 +00:00
committed by intellij-monorepo-bot
parent 948c111e94
commit 84653d683a
4 changed files with 63 additions and 4 deletions
@@ -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<PsiMethod>() != null || expression?.findParentOfType<PsiLocalVariable>() != null) return expression
+3 -1
View File
@@ -198,7 +198,9 @@ c:com.intellij.codeInsight.actions.VcsFacade
- com.intellij.codeInsight.completion.command.commands.ActionCommandProvider
- <init>(java.lang.String,java.lang.String,java.lang.String,java.util.List):V
- b:<init>(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
@@ -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?
}
@@ -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,