From 3ecfea2898d1277873ceed96e5776862c4263828 Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Mon, 29 Sep 2025 17:59:08 +0200 Subject: [PATCH] [command-completion] IJ-CR-176087 IDEA-379364 Go to command should put caret at the end of an identifier - delete unnecessary annotations - improve `selectItem` GitOrigin-RevId: fc66dce8d56eac5d0580acdf42ac8790e0cfaffd --- .../analysis-api/api-dump-experimental.txt | 2 +- .../command/CommandCompletionFactory.kt | 1 - .../AbstractActionCompletionCommand.kt | 1 - .../commands/K2CommandCompletionGoToTest.kt | 23 ++------ .../K2CommandCompletionSurroundWithTest.kt | 19 +------ .../commands/K2CommandCompletionTest.kt | 53 ++++++++++--------- 6 files changed, 32 insertions(+), 67 deletions(-) diff --git a/platform/analysis-api/api-dump-experimental.txt b/platform/analysis-api/api-dump-experimental.txt index 51f1e9edf8a3..2ae40d4cee3b 100644 --- a/platform/analysis-api/api-dump-experimental.txt +++ b/platform/analysis-api/api-dump-experimental.txt @@ -2,7 +2,7 @@ a:com.intellij.codeInsight.completion.CompletionService - *p:getVariantsFromGroupContributors(com.intellij.codeInsight.completion.CompletionParameters,com.intellij.codeInsight.completion.PrefixMatcher,com.intellij.util.Consumer):V *:com.intellij.codeInsight.completion.command.CommandCompletionFactory - com.intellij.openapi.project.PossiblyDumbAware -- *:adjustCaret(com.intellij.psi.PsiFile,I):java.lang.Integer +- adjustCaret(com.intellij.psi.PsiFile,I):java.lang.Integer - commandProviders(com.intellij.openapi.project.Project,com.intellij.lang.Language):java.util.List - createFile(com.intellij.psi.PsiFile,java.lang.String):com.intellij.psi.PsiFile - filterSuffix():java.lang.Character diff --git a/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandCompletionFactory.kt b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandCompletionFactory.kt index ffee63763854..b95f0c39fbb2 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandCompletionFactory.kt +++ b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandCompletionFactory.kt @@ -78,7 +78,6 @@ interface CommandCompletionFactory : PossiblyDumbAware { * Adjust the caret position after GoTo command completion. * @return the new caret position or null if no adjustment is needed */ - @ApiStatus.Experimental fun adjustCaret(psiFile: PsiFile, offset: Int): Int? { val element = psiFile.findElementAt(offset) ?: return null if (element.textRange.startOffset != offset) return null diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractActionCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractActionCompletionCommand.kt index d6b2f789d312..bde432cc9f5b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractActionCompletionCommand.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractActionCompletionCommand.kt @@ -214,7 +214,6 @@ open class ActionCompletionCommand( return null } - @ApiStatus.Experimental @ApiStatus.Internal protected open fun customizeEvent(event: AnActionEvent) { } diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionGoToTest.kt b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionGoToTest.kt index 2e75e585b071..260f7f32c49a 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionGoToTest.kt +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionGoToTest.kt @@ -1,15 +1,10 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.fir.completion.commands -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupEvent -import com.intellij.codeInsight.lookup.impl.LookupImpl import com.intellij.openapi.application.impl.NonBlockingReadActionImpl import com.intellij.openapi.util.registry.Registry -import com.intellij.testFramework.PlatformTestUtil import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import java.util.concurrent.TimeUnit class K2CommandCompletionGoToTest : KotlinLightCodeInsightFixtureTestCase() { override val pluginMode = KotlinPluginMode.K2 @@ -36,7 +31,7 @@ class K2CommandCompletionGoToTest : KotlinLightCodeInsightFixtureTestCase() { }""".trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Go to super", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Go to super", ignoreCase = true) }) myFixture.checkResult( """ open class TestSuper { @@ -63,7 +58,7 @@ class K2CommandCompletionGoToTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Go to decl", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Go to decl", ignoreCase = true) }) myFixture.checkResult( """ fun main() { @@ -92,7 +87,7 @@ class K2CommandCompletionGoToTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Go to impl", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Go to impl", ignoreCase = true) }) NonBlockingReadActionImpl.waitForAsyncTaskCompletion() myFixture.checkResult( """ @@ -110,16 +105,4 @@ class K2CommandCompletionGoToTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) } - - private fun selectItem(item: LookupElement, completionChar: Char = 0.toChar()) { - val lookup: LookupImpl = myFixture.lookup as LookupImpl - lookup.setCurrentItem(item) - if (LookupEvent.isSpecialCompletionChar(completionChar)) { - lookup.finishLookup(completionChar) - } else { - myFixture.type(completionChar) - } - NonBlockingReadActionImpl.waitForAsyncTaskCompletion() - PlatformTestUtil.waitForAllDocumentsCommitted(10, TimeUnit.SECONDS) - } } \ No newline at end of file diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionSurroundWithTest.kt b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionSurroundWithTest.kt index 8fdc37037731..de7ee93a90c3 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionSurroundWithTest.kt +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionSurroundWithTest.kt @@ -1,15 +1,10 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.fir.completion.commands -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupEvent -import com.intellij.codeInsight.lookup.impl.LookupImpl import com.intellij.openapi.application.impl.NonBlockingReadActionImpl import com.intellij.openapi.util.registry.Registry -import com.intellij.testFramework.PlatformTestUtil import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import java.util.concurrent.TimeUnit class K2CommandCompletionSurroundWithTest : KotlinLightCodeInsightFixtureTestCase() { override val pluginMode = KotlinPluginMode.K2 @@ -45,7 +40,7 @@ class K2CommandCompletionSurroundWithTest : KotlinLightCodeInsightFixtureTestCas """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Surround with 'If'", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Surround with 'If'", ignoreCase = true) }) NonBlockingReadActionImpl.waitForAsyncTaskCompletion() myFixture.checkResult( """ @@ -72,16 +67,4 @@ class K2CommandCompletionSurroundWithTest : KotlinLightCodeInsightFixtureTestCas val elements = myFixture.completeBasic() assertNull(elements.firstOrNull { element -> element.lookupString.contains("Surround with 'If'", ignoreCase = true) } ) } - - private fun selectItem(item: LookupElement, completionChar: Char = 0.toChar()) { - val lookup: LookupImpl = myFixture.lookup as LookupImpl - lookup.setCurrentItem(item) - if (LookupEvent.isSpecialCompletionChar(completionChar)) { - lookup.finishLookup(completionChar) - } else { - myFixture.type(completionChar) - } - NonBlockingReadActionImpl.waitForAsyncTaskCompletion() - PlatformTestUtil.waitForAllDocumentsCommitted(10, TimeUnit.SECONDS) - } } \ No newline at end of file diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionTest.kt b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionTest.kt index 280c2402d9b0..e1f7c102ce6b 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionTest.kt +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/commands/K2CommandCompletionTest.kt @@ -12,10 +12,10 @@ import com.intellij.openapi.application.impl.NonBlockingReadActionImpl import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.registry.Registry import com.intellij.testFramework.PlatformTestUtil +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import java.util.concurrent.TimeUnit class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { override val pluginMode = KotlinPluginMode.K2 @@ -35,7 +35,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Change type of", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Change type of", ignoreCase = true) }) myFixture.checkResult( """ fun main() { @@ -207,7 +207,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.equals("Reformat code", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.equals("Reformat code", ignoreCase = true) }) myFixture.checkResult( """ fun main() { @@ -227,7 +227,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Comment with line", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Comment with line", ignoreCase = true) }) myFixture.checkResult( """ //fun main() { @@ -247,7 +247,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Comment with block", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Comment with block", ignoreCase = true) }) myFixture.checkResult( """ /* @@ -269,7 +269,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Delete", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Delete", ignoreCase = true) }) myFixture.checkResult( "" ) @@ -285,7 +285,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Generate 'Secondary", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Generate 'Secondary", ignoreCase = true) }) myFixture.checkResult( """ class A{ @@ -316,7 +316,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Copy ref", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Copy ref", ignoreCase = true) }) myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE) myFixture.checkResult( """ @@ -350,7 +350,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { }""".trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Introduce parameter", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Introduce parameter", ignoreCase = true) }) myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE) myFixture.checkResult( """ @@ -482,7 +482,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) myFixture.checkResult( """ fun bar() { @@ -506,7 +506,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) myFixture.checkResult( """ fun bar() { @@ -530,7 +530,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) myFixture.checkResult( """ fun bar() { @@ -551,7 +551,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent() ) val elements = myFixture.completeBasic() - selectItem(elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) }) myFixture.checkResult( """ fun bar(): Int { @@ -606,7 +606,7 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { myFixture.type(".aaaa") val elements = myFixture.completeBasic() TemplateManagerImpl.setTemplateTesting(myFixture.testRootDisposable) - selectItem(elements.first { element -> element.lookupString.contains("Create method", ignoreCase = true) }) + selectItem(myFixture, elements.first { element -> element.lookupString.contains("Create method", ignoreCase = true) }) NonBlockingReadActionImpl.waitForAsyncTaskCompletion() myFixture.checkResult( @@ -765,17 +765,18 @@ class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() { val elements = myFixture.completeBasic() assertTrue(elements.any { element -> element.lookupString.contains("Optimize im", ignoreCase = true) }) } +} - private fun selectItem(item: LookupElement, completionChar: Char = 0.toChar()) { - val lookup: LookupImpl = myFixture.lookup as LookupImpl - lookup.setCurrentItem(item) - if (LookupEvent.isSpecialCompletionChar(completionChar)) { - lookup.finishLookup(completionChar) - } else { - myFixture.type(completionChar) - } - NonBlockingReadActionImpl.waitForAsyncTaskCompletion() - PlatformTestUtil.waitForAllDocumentsCommitted(10, TimeUnit.SECONDS) +internal fun selectItem(fixture: JavaCodeInsightTestFixture, + item: LookupElement, + completionChar: Char = 0.toChar()) { + val lookup: LookupImpl = fixture.lookup as LookupImpl + lookup.setCurrentItem(item) + if (LookupEvent.isSpecialCompletionChar(completionChar)) { + lookup.finishLookup(completionChar) + } else { + fixture.type(completionChar) } - -} \ No newline at end of file + NonBlockingReadActionImpl.waitForAsyncTaskCompletion() + PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue() +}