mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] KTIJ-33049 Initial support command completion for kotlin
GitOrigin-RevId: 53f1d4411940cf0f8b516dc2fe5949b9da482a32
This commit is contained in:
committed by
intellij-monorepo-bot
parent
260c4da89a
commit
230e228215
+13
-5
@@ -3,22 +3,23 @@ package com.intellij.codeInsight.completion.command.commands
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
|
||||
internal class PsiElementCommentCompletionCommand : AbstractActionCompletionCommand("CommentByLineComment",
|
||||
"Comment element",
|
||||
CodeInsightBundle.message("command.completion.psi.element.comment.text"),
|
||||
CodeInsightBundle.message(
|
||||
"command.completion.psi.element.comment.text"),
|
||||
null) {
|
||||
|
||||
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
|
||||
if (!super.isApplicable(offset, psiFile, editor)) return false
|
||||
val fileDocument = psiFile.fileDocument
|
||||
val immutableCharSequence = fileDocument.immutableCharSequence
|
||||
if (offset - 1 < 0) return false
|
||||
val ch = immutableCharSequence[offset - 1]
|
||||
if (ch != '}' && ch != ']' && ch != ')') return false
|
||||
val context = getHighLevelContext(offset, psiFile) ?: return false
|
||||
if (PsiTreeUtil.skipWhitespacesBackward(context) is PsiComment) return true
|
||||
val startLineNumber = fileDocument.getLineNumber(context.textRange.startOffset)
|
||||
val endLineNumber = fileDocument.getLineNumber(context.textRange.endOffset)
|
||||
return startLineNumber != endLineNumber
|
||||
@@ -42,7 +43,14 @@ internal class PsiElementCommentCompletionCommand : AbstractActionCompletionComm
|
||||
val selectionModel = editor.selectionModel
|
||||
val highLevelContext = getHighLevelContext(offset, psiFile) ?: return
|
||||
val textRange = highLevelContext.textRange
|
||||
selectionModel.setSelection(textRange.startOffset, textRange.endOffset)
|
||||
var startOffset = textRange.startOffset
|
||||
val endOffset = textRange.endOffset
|
||||
var current: PsiElement? = highLevelContext
|
||||
while (current is PsiComment) {
|
||||
startOffset = current.textRange.endOffset
|
||||
current = PsiTreeUtil.skipWhitespacesBackward(current)
|
||||
}
|
||||
selectionModel.setSelection(startOffset, endOffset)
|
||||
super.execute(offset, psiFile, editor)
|
||||
selectionModel.removeSelection()
|
||||
}
|
||||
|
||||
+3
-1
@@ -11,6 +11,7 @@ import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.originalFileOrSelf
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindFilter
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindMatcher
|
||||
@@ -53,7 +54,8 @@ internal class RootKindMatcherImpl(private val project: Project) : RootKindMatch
|
||||
nameSequence.endsWith(BuiltInSerializerProtocol.DOT_DEFAULT_EXTENSION) ||
|
||||
nameSequence.endsWith(DOT_METADATA_FILE_EXTENSION)
|
||||
|
||||
if (virtualFile !is VirtualFileWindow && !hasBinaryFileExtension && fileIndex.isUnderSourceRootOfType(virtualFile, rootType)) {
|
||||
if (virtualFile !is VirtualFileWindow && !hasBinaryFileExtension &&
|
||||
fileIndex.isUnderSourceRootOfType(virtualFile.originalFileOrSelf(), rootType)) {
|
||||
return filter.includeProjectSourceFiles
|
||||
}
|
||||
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.CommandCompletionFactory
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import org.jetbrains.kotlin.idea.base.psi.copied
|
||||
import org.jetbrains.kotlin.psi.KtContainerNode
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
|
||||
class KotlinCommandCompletionFactory : CommandCompletionFactory, DumbAware {
|
||||
override fun isApplicable(psiFile: PsiFile, offset: Int): Boolean {
|
||||
if (psiFile !is KtFile) return false
|
||||
var element = psiFile.findElementAt(offset)
|
||||
val parent = element?.parent
|
||||
if (parent !is KtForExpression) return true
|
||||
element = element.prevSibling?.let {
|
||||
if (it is KtContainerNode) it.firstChild else it
|
||||
} ?: return true
|
||||
return !parent.loopRange.isAncestor(element)
|
||||
}
|
||||
|
||||
override fun createFile(originalFile: PsiFile, text: String): PsiFile? {
|
||||
val newFile = KtPsiFactory.contextual(originalFile, eventSystemEnabled = true).createFile(originalFile.name, text)
|
||||
newFile.originalFile = originalFile
|
||||
if (originalFile.name.endsWith(".kts")) {
|
||||
createCopyOfScript(originalFile, newFile)?.let { return it }
|
||||
}
|
||||
|
||||
val virtualFile = newFile.virtualFile
|
||||
val originalVirtualFile = originalFile.virtualFile
|
||||
if (virtualFile is LightVirtualFile && originalVirtualFile != null) {
|
||||
virtualFile.originalFile = originalVirtualFile
|
||||
virtualFile.fileType = originalVirtualFile.fileType
|
||||
|
||||
}
|
||||
return newFile
|
||||
}
|
||||
|
||||
private fun createCopyOfScript(originalFile: PsiFile, newFile: KtFile): KtFile? {
|
||||
// We copy the original file, which retains the correct script context
|
||||
val newFileCopy = originalFile.copied() as KtFile
|
||||
// replace the old script block with the new script block
|
||||
val copyOfOriginalBlockExpression = newFileCopy.script?.blockExpression ?: return null
|
||||
val copiedNewBlockExpression = newFile.script?.blockExpression ?: return null
|
||||
copyOfOriginalBlockExpression.replace(copiedNewBlockExpression.copy())
|
||||
return newFileCopy
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractCopyFQNCompletionCommand
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver.Companion.tokenType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
class KotlinCopyFQNCompletionCommand : AbstractCopyFQNCompletionCommand() {
|
||||
override fun placeIsApplicable(element: PsiElement, offset: Int): Boolean {
|
||||
if (element.tokenType != KtTokens.IDENTIFIER) return false
|
||||
val member = element.parentOfType<KtNamedDeclaration>()
|
||||
val name = member?.nameIdentifier ?: return false
|
||||
val fileDocument = element.containingFile.fileDocument
|
||||
return fileDocument.getLineNumber(name.textRange.startOffset) == fileDocument.getLineNumber(offset)
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.actions.ReformatCodeProcessor
|
||||
import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
|
||||
import com.intellij.idea.ActionsBundle
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import javax.swing.Icon
|
||||
|
||||
class KotlinDeleteCompletionCommand : ApplicableCompletionCommand(), DumbAware {
|
||||
override val name: String
|
||||
get() = "Delete"
|
||||
override val i18nName: @Nls String
|
||||
get() = ActionsBundle.message("action.EditorDelete.text")
|
||||
override val icon: Icon?
|
||||
get() = null
|
||||
|
||||
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
|
||||
val element = getContext(offset, psiFile) ?: return false
|
||||
val psiElement = PsiTreeUtil.getParentOfType(element, KtExpression::class.java, KtNamedDeclaration::class.java) ?: return false
|
||||
return psiElement.textRange.endOffset == offset
|
||||
}
|
||||
|
||||
override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
|
||||
val element = getContext(offset, psiFile) ?: return
|
||||
var psiElement = PsiTreeUtil.getParentOfType(element, KtExpression::class.java, KtNamedDeclaration::class.java) ?: return
|
||||
var curElement = psiElement
|
||||
while (curElement.textRange.endOffset == offset) {
|
||||
psiElement = curElement
|
||||
curElement = PsiTreeUtil.getParentOfType(curElement, KtExpression::class.java, KtNamedDeclaration::class.java) ?: break
|
||||
}
|
||||
WriteCommandAction.runWriteCommandAction(psiFile.project, null, null, {
|
||||
val parent: SmartPsiElementPointer<PsiElement?> = SmartPointerManager.createPointer(psiElement.parent ?: psiFile)
|
||||
psiElement.delete()
|
||||
PsiDocumentManager.getInstance(psiFile.project).commitDocument(psiFile.fileDocument)
|
||||
parent.element?.let {
|
||||
ReformatCodeProcessor(psiFile, arrayOf(it.textRange)).run()
|
||||
}
|
||||
}, psiFile)
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractFormatCodeCompletionCommand
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parents
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
class KotlinFormatCodeCompletionCommand : AbstractFormatCodeCompletionCommand() {
|
||||
override fun findTargetToRefactor(element: PsiElement): PsiElement {
|
||||
return element.parents(true).first {
|
||||
(it is KtDeclaration || it is KtExpression)
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractGenerateCommandProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassBody
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class KotlinGenerateCommandCompletion : AbstractGenerateCommandProvider() {
|
||||
override fun generationIsAvailable(element: PsiElement, offset: Int): Boolean {
|
||||
val parent = element.parent
|
||||
if (parent !is KtClass && parent !is KtFile && parent !is KtClassBody) return false
|
||||
val onlySpaceInLine = isOnlySpaceInLine(element.containingFile.fileDocument, offset)
|
||||
if (onlySpaceInLine) return true
|
||||
if (parent is KtClass && parent.nameIdentifier == element) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractGoToDeclarationCompletionCommand
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver.Companion.tokenType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
|
||||
class KotlinGoToDeclarationCommandCompletion : AbstractGoToDeclarationCompletionCommand() {
|
||||
override fun canNavigateToDeclaration(context: PsiElement): Boolean {
|
||||
if (context.tokenType != KtTokens.IDENTIFIER) return false
|
||||
val ref = context.parentOfType<KtReferenceExpression>() ?: return false
|
||||
analyze(ref) {
|
||||
return ref.mainReference.resolve() != null
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractGoToImplementationCompletionCommand
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver.Companion.tokenType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
class KotlinGoToImplementationCommandCompletion : AbstractGoToImplementationCompletionCommand() {
|
||||
override fun canGoToImplementation(element: PsiElement, offset: Int): Boolean {
|
||||
if (element.tokenType != KtTokens.IDENTIFIER) return false
|
||||
val member = element.parentOfType<KtNamedDeclaration>()
|
||||
val name = member?.nameIdentifier ?: return false
|
||||
val fileDocument = element.containingFile.fileDocument
|
||||
return fileDocument.getLineNumber(name.textRange.startOffset) == fileDocument.getLineNumber(offset)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// 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.completion.impl.k2.contributors.commands
|
||||
|
||||
import com.intellij.codeInsight.completion.command.commands.AbstractShowUsagesActionCompletionCommand
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver.Companion.tokenType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
class KotlinShowUsagesActionCompletionCommand : AbstractShowUsagesActionCompletionCommand() {
|
||||
override fun hasToShow(element: PsiElement): Boolean {
|
||||
if (element.tokenType != KtTokens.IDENTIFIER) return false
|
||||
return element.parent is KtNamedDeclaration
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
/**
|
||||
* Package contains experimental implementations for kotlin command completion
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
package org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
// 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
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupEvent
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
|
||||
class K2CommandCompletionTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override val pluginMode = KotlinPluginMode.K2
|
||||
|
||||
fun testRedCompletion() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a: String = 1.<caret>
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Change type of", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
fun main() {
|
||||
val a: Int = 1
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun testFormat() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a: String = "1"
|
||||
}.<caret>
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Format", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
fun main() {
|
||||
val a: String = "1"
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun testComment() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a: String = "1".<caret>
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Comment", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
fun main() {
|
||||
// val a: String = "1"
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun testCommentPsiElement() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a: String = "1"
|
||||
}.<caret>
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Comment element", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
//fun main() {
|
||||
// val a: String = "1"
|
||||
//}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun testDeletePsiElement() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a: String = "1"
|
||||
}.<caret>
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Delete", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
""
|
||||
)
|
||||
}
|
||||
|
||||
fun testGenerate() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A{
|
||||
.<caret>
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Generate 'Secondary", ignoreCase = true) })
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
class A{
|
||||
constructor()
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun testCopyFqn() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
class A.<caret>{
|
||||
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Copy ref", ignoreCase = true) })
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
class AA{
|
||||
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun testGoToDeclaration() {
|
||||
Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
|
||||
myFixture.configureByText(
|
||||
"x.kt", """
|
||||
fun main() {
|
||||
val a = "1"
|
||||
print(a.<caret>)
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
val elements = myFixture.completeBasic()
|
||||
selectItem(elements.first { element -> element.lookupString.contains("Go to decl", ignoreCase = true) })
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
fun main() {
|
||||
val <caret>a = "1"
|
||||
print(a)
|
||||
}
|
||||
""".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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<idea-plugin>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<codeInsight.completion.command.factory language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinCommandCompletionFactory"/>
|
||||
<codeInsight.completion.command.provider language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.SimpleRunMarkerCommandProvider"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.RenameActionCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.OptimizeImportCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.RecentFilesCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.ProjectViewCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.LineCommentCompletionCommand"/>
|
||||
<codeInsight.completion.command.provider language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinGenerateCommandCompletion"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinGoToDeclarationCommandCompletion"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinGoToImplementationCommandCompletion"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinFormatCodeCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinCopyFQNCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinShowUsagesActionCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.commands.PsiElementCommentCompletionCommand"/>
|
||||
<codeInsight.completion.applicable.command language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinDeleteCompletionCommand"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -39,6 +39,10 @@
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
<xi:include href="command-completion-k2.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<scriptAdditionalIdeaDependenciesProvider implementation="org.jetbrains.kotlin.idea.core.script.ModuleScriptAdditionalIdeaDependenciesProvider"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user