[command-completion] IDEA-371054 Add 'inject' completion command

GitOrigin-RevId: 203ecfaa191398c5b438434549c41514ebdb7523
This commit is contained in:
Mikhail Pyltsin
2025-04-22 15:56:31 +00:00
committed by intellij-monorepo-bot
parent de60121067
commit 07eb11c357
4 changed files with 42 additions and 6 deletions
@@ -76,6 +76,9 @@ class JavaCommandCompletionFactory implements CommandCompletionFactory, DumbAwar
}
results.add(currentOffset);
if (element == null) continue;
if (element.getParent() instanceof PsiLiteralExpression literalExpression && literalExpression.getValue() instanceof String) {
results.add(literalExpression.getTextRange().getEndOffset() - (literalExpression.isTextBlock() ? 3 : 1));
}
PsiElement parent = element.getParent();
if (element instanceof PsiJavaToken) {
Character open = braces.get(element.getText().charAt(0));
@@ -22,7 +22,7 @@ internal class IntentionCompletionCommand(
override val highlightInfo: HighlightInfoLookup?,
private val myOffset: Int,
private val previewProvider: () -> IntentionPreviewInfo?,
) : CompletionCommand(), CompletionCommandWithPreview {
) : CompletionCommand(), CompletionCommandWithPreview {
override val name: String
get() = intentionAction.text
@@ -44,8 +44,8 @@ internal class IntentionCompletionCommand(
if (availableFor) {
ShowIntentionActionsHandler.chooseActionAndInvoke(psiFile, editor, intentionAction.action, name)
}
if (targetMarker.isValid && targetMarker.startOffset != editor.caretModel.offset) {
//probably, intention moves the cursor
if (!intentionAction.action.startInWriteAction() || (targetMarker.isValid && targetMarker.startOffset != editor.caretModel.offset)) {
//probably, intention moves the cursor or async gui
return
}
if (marker.isValid) {
@@ -2,9 +2,17 @@
package org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands
import com.intellij.codeInsight.completion.command.CommandCompletionFactory
import com.intellij.codeInsight.completion.command.commands.IntentionCommandOffsetProvider
import com.intellij.openapi.project.DumbAware
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiLanguageInjectionHost
import com.intellij.testFramework.LightVirtualFile
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaImplementationDetail
import org.jetbrains.kotlin.analysis.api.projectStructure.analysisContextModule
import org.jetbrains.kotlin.analysis.api.projectStructure.contextModule
import org.jetbrains.kotlin.idea.base.codeInsight.handlers.fixers.range
import org.jetbrains.kotlin.idea.base.projectStructure.getKaModule
import org.jetbrains.kotlin.idea.base.psi.copied
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
@@ -28,9 +36,11 @@ class KotlinCommandCompletionFactory : CommandCompletionFactory, DumbAware {
return true
}
@OptIn(KaImplementationDetail::class, KaExperimentalApi::class)
override fun createFile(originalFile: PsiFile, text: String): PsiFile? {
val newFile = KtPsiFactory.contextual(originalFile, eventSystemEnabled = true).createFile(originalFile.name, text)
newFile.originalFile = originalFile
val newFile =
KtPsiFactory(originalFile.project, eventSystemEnabled = true, markGenerated = false).createFile(originalFile.name, text)
newFile.contextModule = originalFile.getKaModule(originalFile.project, useSiteModule = null)
if (originalFile.name.endsWith(".kts")) {
createCopyOfScript(originalFile, newFile)?.let { return it }
}
@@ -38,9 +48,9 @@ class KotlinCommandCompletionFactory : CommandCompletionFactory, DumbAware {
val virtualFile = newFile.virtualFile
val originalVirtualFile = originalFile.virtualFile
if (virtualFile is LightVirtualFile && originalVirtualFile != null) {
virtualFile.analysisContextModule = originalFile.getKaModule(originalFile.project, useSiteModule = null)
virtualFile.originalFile = originalVirtualFile
virtualFile.fileType = originalVirtualFile.fileType
}
return newFile
}
@@ -54,4 +64,24 @@ class KotlinCommandCompletionFactory : CommandCompletionFactory, DumbAware {
copyOfOriginalBlockExpression.replace(copiedNewBlockExpression.copy())
return newFileCopy
}
class KotlinIntentionCommandOffsetProvider : IntentionCommandOffsetProvider {
override fun findOffsets(psiFile: PsiFile, offset: Int): List<Int> {
val offsets = mutableListOf<Int>()
offsets.add(offset)
if (offset == 0) {
return offsets
}
val previousElement = psiFile.findElementAt(offset - 1)
if (previousElement?.parent is PsiLanguageInjectionHost) {
val delta = if (previousElement.parent.text.endsWith("\"\"\"")) {
3
} else {
1
}
offsets.add(previousElement.parent.range.endOffset - delta)
}
return offsets
}
}
}
@@ -1,6 +1,9 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<codeInsight.completion.intention.offset.provider language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinCommandCompletionFactory$KotlinIntentionCommandOffsetProvider"/>
<codeInsight.completion.command.factory language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.completion.impl.k2.contributors.commands.KotlinCommandCompletionFactory"/>
<!-- <codeInsight.completion.command.provider language="kotlin"-->