diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index 6bd34c9cddc1..e2a2914b1a4e 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -292,20 +292,6 @@
-
-
-
-
-
-
-
-
-
@@ -1503,29 +1489,29 @@
implementationClass="com.intellij.codeInsight.completion.JvmLoggerCompletionContributor"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2790,17 +2776,6 @@
-
-
-
-
-
-
-
-
-
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/JavaCommandCompletionFactory.java b/java/java-impl/src/com/intellij/codeInsight/completion/commands/JavaCommandCompletionFactory.java
new file mode 100644
index 000000000000..4e732d522383
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/JavaCommandCompletionFactory.java
@@ -0,0 +1,46 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.commands;
+
+import com.intellij.codeInsight.completion.command.CommandCompletionFactory;
+import com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper;
+import com.intellij.codeInsight.daemon.impl.quickfix.CreateGetterOrSetterFix;
+import com.intellij.codeInsight.daemon.impl.quickfix.ExpensivePsiIntentionAction;
+import com.intellij.codeInsight.intention.CommonIntentionAction;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ex.QuickFixWrapper;
+import com.intellij.modcommand.ModCommandAction;
+import com.intellij.modcommand.ModCommandService;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.NotNull;
+
+public class JavaCommandCompletionFactory implements CommandCompletionFactory, DumbAware {
+
+ @Override
+ public boolean isApplicable(@NotNull PsiFile psiFile, int offset) {
+ //todo skip varargs!
+ if (!(psiFile instanceof PsiJavaFile)) return false;
+ PsiElement elementAt = psiFile.findElementAt(offset);
+ if (elementAt == null) return true;
+ if (!(elementAt.getParent() instanceof PsiParameterList)) return true;
+ PsiElement prevLeaf = PsiTreeUtil.prevLeaf(elementAt, true);
+ if (!(prevLeaf instanceof PsiJavaToken javaToken && javaToken.textMatches("."))) return true;
+ PsiElement prevPrevLeaf = PsiTreeUtil.prevLeaf(prevLeaf, true);
+ if (PsiTreeUtil.getParentOfType(prevPrevLeaf, PsiTypeElement.class) != null) return false;
+ return true;
+ }
+
+ public static class JavaIntentionCommandSkipper implements IntentionCommandSkipper {
+ @Override
+ public boolean skip(@NotNull CommonIntentionAction action, @NotNull PsiFile psiFile, int offset) {
+ if (action instanceof ExpensivePsiIntentionAction) return true;
+ LocalQuickFix fix = QuickFixWrapper.unwrap(action);
+ if (fix != null) {
+ ModCommandAction unwrappedAction = ModCommandService.getInstance().unwrap(fix);
+ if (unwrappedAction instanceof CreateGetterOrSetterFix) return true;
+ }
+ return IntentionCommandSkipper.super.skip(action, psiFile, offset);
+ }
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandCompletionFactory.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandCompletionFactory.kt
deleted file mode 100644
index eb7df4433aef..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandCompletionFactory.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.api
-
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiFile
-import org.jetbrains.annotations.ApiStatus
-
-/**
- * Factory interface for creating and managing completion commands in a specific context.
- *
- * Provides functionality to determine applicability based on the file and offset,
- * retrieve a list of command providers, and define suffixes used during code completion.
- * Serves as a customization point for enhancing code completion workflows.
- *
- * Should implement DumbAware to support dumb mode
- */
-@ApiStatus.Experimental
-interface CommandCompletionFactory {
- /**
- * Provides the default character suffix. After that, suffix command completion will be enabled
- *
- * @return The character suffix, which is '.'.
- */
- fun suffix(): Char = '.'
-
- /**
- * Determines the character suffix to filter only command lookup
- */
- fun filterSuffix(): Char? = '.'
-
- /**
- * Retrieves a list of command providers responsible for supplying completion commands.
- */
- fun commandProviders(project: Project): List
-
- /**
- * Determines whether the functionality is applicable in the given context.
- *
- * @param psiFile the PSI file representing the file in which the applicability is being evaluated
- * @param offset the position within the file where the applicability should be checked
- * @return true if the functionality is applicable at the specified context, false otherwise
- */
- fun isApplicable(psiFile: PsiFile, offset: Int): Boolean
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionLookupElement.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionLookupElement.kt
deleted file mode 100644
index edf717718c29..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionLookupElement.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
-
-import com.intellij.codeInsight.lookup.AutoCompletionPolicy
-import com.intellij.codeInsight.lookup.AutoCompletionPolicy.NEVER_AUTOCOMPLETE
-import com.intellij.codeInsight.lookup.LookupElement
-import com.intellij.codeInsight.lookup.LookupElementDecorator
-import com.intellij.openapi.editor.colors.TextAttributesKey
-import com.intellij.openapi.util.TextRange
-import org.jetbrains.annotations.ApiStatus
-import javax.swing.Icon
-
-@ApiStatus.Experimental
-class CommandCompletionLookupElement(
- lookupElement: LookupElement,
- val hostStartOffset: Int,
- val suffix: String,
- val icon: Icon?,
- val highlighting: HighlightInfoLookup?,
-) : LookupElementDecorator(lookupElement) {
- override fun isWorthShowingInAutoPopup(): Boolean {
- return true
- }
-
- override fun getAutoCompletionPolicy(): AutoCompletionPolicy? {
- return NEVER_AUTOCOMPLETE
- }
-}
-
-@ApiStatus.Experimental
-data class HighlightInfoLookup(
- val range: TextRange,
- val attributesKey: TextAttributesKey,
- val priority: Int, //higher is on the top
-)
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/CopyFQNCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/CopyFQNCompletionCommand.kt
deleted file mode 100644
index 4570f031b691..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/CopyFQNCompletionCommand.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.ide.IdeBundle
-import com.intellij.ide.actions.FqnUtil
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.util.TextRange
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiMember
-import com.intellij.psi.PsiMethod
-import com.intellij.psi.util.PsiTreeUtil
-
-class CopyFQNCompletionCommand : AbstractActionCompletionCommand("CopyReference",
- "Copy Reference",
- IdeBundle.message("copy.reference"),
- null,
- -150) {
- override fun supportsReadOnly(): Boolean = true
-
- override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
- if (!super.isApplicable(offset, psiFile, editor)) return false
- val element = getContext(offset, psiFile)
- val member = PsiTreeUtil.getParentOfType(element, PsiMember::class.java) ?: return false
- if (member is PsiClass) {
- if (!TextRange(member.textRange.startOffset, member.lBrace?.textRange?.startOffset ?: member.textRange.endOffset)
- .contains(offset)
- ) {
- return false
- }
- }
- else if (member is PsiMethod) {
- if (!TextRange(member.textRange.startOffset, member.body?.textRange?.startOffset ?: member.textRange.endOffset)
- .contains(offset)
- ) {
- return false
- }
- }
- else {
- return false
- }
- return FqnUtil.elementToFqn(element, editor) != null
- }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ExtensionBasedCommandProvider.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ExtensionBasedCommandProvider.kt
deleted file mode 100644
index 9fa248941591..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ExtensionBasedCommandProvider.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionProviderContext
-import com.intellij.codeInsight.completion.commands.api.CommandProvider
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.DumbService
-
-
-class ExtensionPointCommandProvider : CommandProvider, DumbAware {
- override fun getCommands(context: CommandCompletionProviderContext): List {
- val completionCommands = DumbService.getDumbAwareExtensions(context.project, ApplicableCompletionCommand.EP_NAME)
- return completionCommands.filter {
- !(context.isReadOnly && !it.supportsReadOnly()) && it.isApplicable(context.offset, context.psiFile, context.editor)
- }
- }
-
- override fun getId(): String {
- return "ExtensionPointCommandProvider"
- }
-
- override fun supportsReadOnly(): Boolean {
- return true
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/FormatCodeCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/FormatCodeCompletionCommand.kt
deleted file mode 100644
index 5281c688c213..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/FormatCodeCompletionCommand.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.codeInsight.actions.ReformatCodeProcessor
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
-import com.intellij.icons.AllIcons
-import com.intellij.idea.ActionsBundle
-import com.intellij.lang.injection.InjectedLanguageManager
-import com.intellij.openapi.editor.Editor
-import com.intellij.psi.PsiCodeBlock
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiMember
-import com.intellij.psi.PsiStatement
-import com.intellij.psi.util.parents
-import org.jetbrains.annotations.Nls
-import javax.swing.Icon
-
-class FormatCodeCompletionCommand : ApplicableCompletionCommand() {
- override val name: String
- get() = "format"
-
- override val i18nName: @Nls String
- get() = ActionsBundle.message("action.ReformatCode.text")
-
- override val icon: Icon
- get() = AllIcons.Actions.ReformatCode // Use the reformat icon
-
- override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
- if (InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)) return false
- return true
- }
-
- override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
- val element = getContext(offset, psiFile) ?: return
- val target = element.parents(true).first { it is PsiMember || it is PsiCodeBlock || it is PsiStatement }
- ReformatCodeProcessor(element.containingFile, arrayOf(target.textRange)).run()
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt
deleted file mode 100644
index 85a95275ef47..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCommandProvider.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.codeInsight.completion.commands.api.*
-import com.intellij.codeInsight.generation.actions.BaseGenerateAction
-import com.intellij.lang.injection.InjectedLanguageManager
-import com.intellij.openapi.actionSystem.*
-import com.intellij.openapi.actionSystem.impl.Utils
-import com.intellij.openapi.editor.Document
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.DumbService
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiIdentifier
-import com.intellij.util.containers.JBIterable.from
-
-
-class GenerateCommandProvider : CommandProvider, DumbAware {
- override fun getCommands(context: CommandCompletionProviderContext): List {
- val psiFile = context.psiFile
- val project = context.project
- val offset = context.offset
- val editor = context.editor
- if (InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)) return emptyList()
- val element = psiFile.findElementAt(if (offset - 1 >= 0) offset - 1 else offset)
- val parent = element?.parent
- //skip, probably extension to skip?
- if (element == null || parent !is PsiClass) return emptyList()
- if (!isOnlySpaceInLine(psiFile.fileDocument, offset) &&
- !(element is PsiIdentifier && parent.nameIdentifier == element)) return emptyList()
- val context = getTargetContext(offset, editor)
- val dataContext = getDataContext(psiFile, editor, context)
- val actionEvent = AnActionEvent.createEvent(dataContext, null, ActionPlaces.UNKNOWN, ActionUiKind.NONE, null)
- actionEvent.updateSession = UpdateSession.EMPTY
- Utils.initUpdateSession(actionEvent)
- val generateActions: MutableList = ArrayList()
- val session = actionEvent.updateSession
- val dumbService = DumbService.getInstance(project)
- val activeActions = from(session.expandedChildren(ActionManager.getInstance().getAction(IdeActions.GROUP_GENERATE) as ActionGroup))
- .filter { dumbService.isUsableInCurrentContext(it) }
- .filter { o: AnAction? -> o !is Separator && o != null && session.presentation(o).isEnabledAndVisible }
- for (action in activeActions) {
- if (action is BaseGenerateAction) {
- generateActions.add(action)
- }
- }
- return generateActions.map { GenerateCompletionCommand(it) }
- }
-
- private fun isOnlySpaceInLine(document: Document, offset: Int): Boolean {
- val lineNumber = document.getLineNumber(offset)
- val lineStartOffset = document.getLineStartOffset(lineNumber)
- val immutableCharSequence = document.immutableCharSequence
- for (i in lineStartOffset..offset) {
- if (!immutableCharSequence[i].isWhitespace()) {
- return false
- }
- }
- return true
- }
-
- override fun getId(): String {
- return "GenerateCommandProvider"
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt
deleted file mode 100644
index 3816dbdbb9ef..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GenerateCompletionCommand.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.codeInsight.generation.actions.BaseGenerateAction
-import com.intellij.ide.DataManager
-import com.intellij.java.JavaBundle
-import com.intellij.openapi.actionSystem.ActionPlaces
-import com.intellij.openapi.actionSystem.ActionUiKind
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.Presentation
-import com.intellij.openapi.actionSystem.ex.ActionUtil
-import com.intellij.openapi.editor.Editor
-import com.intellij.psi.PsiFile
-import org.jetbrains.annotations.Nls
-import javax.swing.Icon
-
-
-class GenerateCompletionCommand(private val action: BaseGenerateAction) : CompletionCommand() {
- override val name: String
- get() = "Generate \'" + action.templateText + "\'"
- override val i18nName: @Nls String
- get() = JavaBundle.message(
- "command.completion.generate.text",
- action.templateText)
- override val icon: Icon?
- get() = null
-
- override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
- if (editor == null) return
- val dataContext = DataManager.getInstance().getDataContext(editor.getComponent())
- val presentation: Presentation = action.templatePresentation.clone()
- val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.UNKNOWN, ActionUiKind.NONE, null)
- if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
- ActionUtil.performActionDumbAwareWithCallbacks(action, event)
- }
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt
deleted file mode 100644
index 5e7c5df2bf90..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToDeclarationCompletionCommand.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.idea.ActionsBundle
-import com.intellij.openapi.editor.Editor
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiIdentifier
-import com.intellij.psi.PsiJavaCodeReferenceElement
-import com.intellij.psi.util.PsiTreeUtil
-
-class GoToDeclarationCompletionCommand : AbstractActionCompletionCommand("GotoDeclarationOnly",
- "Go to Declaration",
- ActionsBundle.message("action.GotoDeclarationOnly.text"),
- null) {
- override fun supportsReadOnly(): Boolean = true
-
- override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
- return super.isApplicable(offset, psiFile, editor) && hasToShow(offset, psiFile)
- }
-
- private fun hasToShow(offset: Int, psiFile: PsiFile): Boolean {
- val context = (getContext(offset, psiFile)) ?: return false
- return canNavigateToDeclaration(context)
- }
-
- private fun canNavigateToDeclaration(context: PsiElement): Boolean {
- if (context !is PsiIdentifier) {
- return false
- }
- val javaRef = PsiTreeUtil.getParentOfType(context, PsiJavaCodeReferenceElement::class.java)
- val psiElement = javaRef?.resolve()
- return psiElement != null
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaBaseGenerateGetterSetterHandleCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaBaseGenerateGetterSetterHandleCompletionCommand.kt
index 5437b38fbfc3..f2af22c58982 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaBaseGenerateGetterSetterHandleCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaBaseGenerateGetterSetterHandleCompletionCommand.kt
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.completion.commands.impl
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
@@ -15,15 +15,15 @@ import javax.swing.Icon
class GenerateGetterSetterHandleCompletionCommand :
- BaseGenerateGetterSetterHandleCompletionCommand(true, true, "Create Getter/Setter",
+ BaseGenerateGetterSetterHandleCompletionCommand(true, true, "Generate 'Getter/Setter'",
QuickFixBundle.message("create.getter.setter"))
class GenerateSetterHandleCompletionCommand :
- BaseGenerateGetterSetterHandleCompletionCommand(false, true, "Create Setter",
+ BaseGenerateGetterSetterHandleCompletionCommand(false, true, "Generate 'Setter'",
QuickFixBundle.message("create.setter"))
class GenerateGetterHandleCompletionCommand :
- BaseGenerateGetterSetterHandleCompletionCommand(true, false, "Create Getter",
+ BaseGenerateGetterSetterHandleCompletionCommand(true, false, "Generate 'Getter'",
QuickFixBundle.message("create.getter"))
abstract class BaseGenerateGetterSetterHandleCompletionCommand(
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCommandCompletionFactory.java b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCommandCompletionFactory.java
deleted file mode 100644
index 457c2d95d187..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCommandCompletionFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl;
-
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionFactory;
-import com.intellij.codeInsight.completion.commands.api.CommandProvider;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.DumbService;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.registry.Registry;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiJavaFile;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class JavaCommandCompletionFactory implements CommandCompletionFactory, DumbAware {
-
- @Override
- public @NotNull List<@NotNull CommandProvider> commandProviders(@NotNull Project project) {
- if (!Registry.is("java.completion.command.enabled")) return List.of();
-
- return DumbService.getDumbAwareExtensions(project, CommandProvider.Companion.getEP_NAME());
- }
-
- @Override
- public boolean isApplicable(@NotNull PsiFile psiFile, int offset) {
- return psiFile instanceof PsiJavaFile;
- }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToImplementationCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCopyFQNCompletionCommand.kt
similarity index 51%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToImplementationCompletionCommand.kt
rename to java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCopyFQNCompletionCommand.kt
index 3fb05f79f7eb..3442d025fddc 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/GoToImplementationCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaCopyFQNCompletionCommand.kt
@@ -1,24 +1,18 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.completion.commands.impl
-import com.intellij.idea.ActionsBundle
-import com.intellij.openapi.editor.Editor
+import com.intellij.codeInsight.completion.command.commands.AbstractCopyFQNCompletionCommand
+import com.intellij.ide.actions.FqnUtil
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.util.PsiTreeUtil
-class GoToImplementationCompletionCommand: AbstractActionCompletionCommand("GotoImplementation",
- "Go to Implementation",
- ActionsBundle.message("action.GotoImplementation.text"),
- null) {
- override fun supportsReadOnly(): Boolean = true
-
- override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
- if (!super.isApplicable(offset, psiFile, editor)) return false
- val element = getContext(offset, psiFile)
+class JavaCopyFQNCompletionCommand : AbstractCopyFQNCompletionCommand() {
+ override fun placeIsApplicable(element: PsiElement, offset: Int): Boolean {
+ if (FqnUtil.elementToFqn(element, null) == null) return false
val member = PsiTreeUtil.getParentOfType(element, PsiMember::class.java) ?: return false
if (member is PsiClass) {
if (!TextRange(member.textRange.startOffset, member.lBrace?.textRange?.startOffset ?: member.textRange.endOffset)
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DeleteCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaDeleteCompletionCommand.kt
similarity index 92%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DeleteCompletionCommand.kt
rename to java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaDeleteCompletionCommand.kt
index fabff80bd552..48e642f10170 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DeleteCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaDeleteCompletionCommand.kt
@@ -2,7 +2,7 @@
package com.intellij.codeInsight.completion.commands.impl
import com.intellij.codeInsight.actions.ReformatCodeProcessor
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
import com.intellij.idea.ActionsBundle
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Editor
@@ -12,7 +12,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.Nls
import javax.swing.Icon
-class DeleteCompletionCommand : ApplicableCompletionCommand(), DumbAware {
+class JavaDeleteCompletionCommand : ApplicableCompletionCommand(), DumbAware {
override val name: String
get() = "Delete"
override val i18nName: @Nls String
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaFormatCodeCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaFormatCodeCompletionCommand.kt
new file mode 100644
index 000000000000..b7690d5d6cde
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaFormatCodeCompletionCommand.kt
@@ -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 com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.completion.command.commands.AbstractFormatCodeCompletionCommand
+import com.intellij.psi.PsiCodeBlock
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMember
+import com.intellij.psi.PsiStatement
+import com.intellij.psi.util.parents
+
+class JavaFormatCodeCompletionCommand : AbstractFormatCodeCompletionCommand() {
+ override fun findTargetToRefactor(element: PsiElement): PsiElement {
+ return element.parents(true).first { it is PsiMember || it is PsiCodeBlock || it is PsiStatement }
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateCommandCompletion.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateCommandCompletion.kt
new file mode 100644
index 000000000000..e6ef2b4b6107
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateCommandCompletion.kt
@@ -0,0 +1,17 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.completion.command.commands.AbstractGenerateCommandProvider
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiIdentifier
+
+class JavaGenerateCommandCompletion : AbstractGenerateCommandProvider() {
+ override fun generationIsAvailable(element: PsiElement, offset: Int): Boolean {
+ val parent = element.parent
+ if (parent !is PsiClass) return false
+ if (!isOnlySpaceInLine(element.containingFile.fileDocument, offset) &&
+ !(element is PsiIdentifier && parent.nameIdentifier == element)) return false
+ return true
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToDeclarationCommandCompletion.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToDeclarationCommandCompletion.kt
new file mode 100644
index 000000000000..fc9003a70b8f
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToDeclarationCommandCompletion.kt
@@ -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 com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.completion.command.commands.AbstractGoToDeclarationCompletionCommand
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiIdentifier
+import com.intellij.psi.PsiJavaCodeReferenceElement
+import com.intellij.psi.util.PsiTreeUtil
+
+class JavaGoToDeclarationCommandCompletion : AbstractGoToDeclarationCompletionCommand() {
+ override fun canNavigateToDeclaration(context: PsiElement): Boolean {
+ if (context !is PsiIdentifier) {
+ return false
+ }
+ val javaRef = PsiTreeUtil.getParentOfType(context, PsiJavaCodeReferenceElement::class.java)
+ val psiElement = javaRef?.resolve()
+ return psiElement != null
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToImplementationCommandCompletion.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToImplementationCommandCompletion.kt
new file mode 100644
index 000000000000..bdcb66130182
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGoToImplementationCommandCompletion.kt
@@ -0,0 +1,35 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.completion.command.commands.AbstractGoToImplementationCompletionCommand
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMember
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.util.PsiTreeUtil
+
+class JavaGoToImplementationCommandCompletion : AbstractGoToImplementationCompletionCommand() {
+ override fun canGoToImplementation(element: PsiElement, offset: Int): Boolean {
+
+ val member = PsiTreeUtil.getParentOfType(element, PsiMember::class.java) ?: return false
+ if (member is PsiClass) {
+ if (!TextRange(member.textRange.startOffset, member.lBrace?.textRange?.startOffset ?: member.textRange.endOffset)
+ .contains(offset)
+ ) {
+ return false
+ }
+ }
+ else if (member is PsiMethod) {
+ if (!TextRange(member.textRange.startOffset, member.body?.textRange?.startOffset ?: member.textRange.endOffset)
+ .contains(offset)
+ ) {
+ return false
+ }
+ }
+ else {
+ return false
+ }
+ return true
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/InlineVariableCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaInlineVariableCompletionCommand.kt
similarity index 92%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/InlineVariableCompletionCommand.kt
rename to java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaInlineVariableCompletionCommand.kt
index f881e9ce18d7..f38fb0ddcc91 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/InlineVariableCompletionCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaInlineVariableCompletionCommand.kt
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.completion.commands.impl
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
import com.intellij.icons.AllIcons
import com.intellij.java.JavaBundle
import com.intellij.lang.refactoring.InlineActionHandler
@@ -13,9 +13,9 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.Nls
import javax.swing.Icon
-class InlineVariableCompletionCommand : ApplicableCompletionCommand() {
+class JavaInlineVariableCompletionCommand : ApplicableCompletionCommand() {
override val name: String
- get() = "inline"
+ get() = "Inline"
override val i18nName: @Nls String
get() = JavaBundle.message("command.completion.inline.text")
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaIntroduceVariableCommand.kt
similarity index 84%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt
rename to java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaIntroduceVariableCommand.kt
index b1250567cfdf..fc056c9814ee 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntroduceVariableCommand.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaIntroduceVariableCommand.kt
@@ -1,9 +1,9 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.completion.commands.impl
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
-import com.intellij.codeInsight.completion.commands.api.getDataContext
-import com.intellij.codeInsight.completion.commands.api.getTargetContext
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+import com.intellij.codeInsight.completion.command.getDataContext
+import com.intellij.codeInsight.completion.command.getTargetContext
import com.intellij.icons.AllIcons
import com.intellij.ide.DataManager
import com.intellij.lang.ContextAwareActionHandler
@@ -20,7 +20,7 @@ import com.intellij.refactoring.actions.IntroduceVariableAction
import org.jetbrains.annotations.Nls
import javax.swing.Icon
-class IntroduceVariableCommand : ApplicableCompletionCommand() {
+class JavaIntroduceVariableCommand : ApplicableCompletionCommand() {
override val name: String
get() = "Introduce variable"
@@ -45,7 +45,7 @@ class IntroduceVariableCommand : ApplicableCompletionCommand() {
if (editor == null) return
val dataContext = DataManager.getInstance().getDataContext(editor.getComponent())
val presentation: Presentation = action.templatePresentation.clone()
- val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
+ val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.Companion.NONE, null)
if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
ActionUtil.performActionDumbAwareWithCallbacks(action, event)
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaShowUsagesActionCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaShowUsagesActionCompletionCommand.kt
new file mode 100644
index 000000000000..d9347018a3cd
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaShowUsagesActionCompletionCommand.kt
@@ -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 com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.completion.command.commands.AbstractShowUsagesActionCompletionCommand
+import com.intellij.psi.*
+import com.intellij.psi.util.PsiTreeUtil
+
+class JavaShowUsagesActionCompletionCommand : AbstractShowUsagesActionCompletionCommand() {
+ override fun hasToShow(element: PsiElement): Boolean {
+ val namedIdentifierParent = PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner::class.java)
+ return namedIdentifierParent?.nameIdentifier == element &&
+ (namedIdentifierParent is PsiVariable || namedIdentifierParent is PsiMethod || namedIdentifierParent is PsiMember)
+
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt
deleted file mode 100644
index 76614d2c6fdb..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ShowUsagesActionCompletionCommand.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
-
-import com.intellij.find.actions.ShowUsagesAction
-import com.intellij.idea.ActionsBundle
-import com.intellij.lang.injection.InjectedLanguageManager
-import com.intellij.openapi.editor.Editor
-import com.intellij.psi.*
-import com.intellij.psi.util.PsiTreeUtil
-
-class ShowUsagesActionCompletionCommand : AbstractActionCompletionCommand(ShowUsagesAction.ID,
- "Show usages",
- ActionsBundle.message("action.ShowUsages.text"),
- null) {
- override fun supportsReadOnly(): Boolean = true
-
- override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
- return super.isApplicable(offset, psiFile, editor) && hasToShow(getContext(offset, psiFile)) &&
- !InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)
- }
-
- private fun hasToShow(element: PsiElement?): Boolean {
- if (element == null) return false
- val namedIdentifierParent = PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner::class.java)
- return namedIdentifierParent?.nameIdentifier == element &&
- (namedIdentifierParent is PsiVariable || namedIdentifierParent is PsiMethod || namedIdentifierParent is PsiMember)
- }
-}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionTest.kt
index d582bb25f6f4..8a7dd98eaa46 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionTest.kt
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionTest.kt
@@ -5,6 +5,7 @@ import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase
import com.intellij.codeInsight.hint.HintManager
import com.intellij.codeInsight.hint.HintManagerImpl
import com.intellij.ide.highlighter.JavaFileType
+import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.impl.NonBlockingReadActionImpl
import com.intellij.openapi.editor.Editor
@@ -21,7 +22,7 @@ import javax.swing.JComponent
class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
fun testFormatNotCall() {
- Registry.get("java.completion.command.enabled").setValue(false, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(false, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -35,7 +36,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testFormat() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -56,8 +57,191 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
""".trimIndent())
}
+ fun testCopyFqn() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ void foo.() {
+ int y = 10;
+ }
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("copy ref", ignoreCase = true) })
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A {
+ void foofoo()() {
+ int y = 10;
+ }
+ }
+ """.trimIndent())
+ }
+
+ fun testGenerateConstructor() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ .
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'Con", ignoreCase = true) })
+ myFixture.checkResult("""
+ class A {
+ public A() {
+ }
+ }
+ """.trimIndent())
+ }
+
+ fun testGenerateConstructorInline() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.full.line.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ generate 'con
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'Con", ignoreCase = true) })
+ myFixture.checkResult("""
+ class A {
+ public A() {
+ }
+ }
+ """.trimIndent())
+ }
+
+ fun testOptimizeImport() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ import java.util.List;
+ .
+ class A {
+ void foo() {
+ String y = "1";
+ }
+ }""".trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Optimize im", ignoreCase = true) })
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A {
+ void foo() {
+ String y = "1";
+ }
+ }""".trimIndent())
+ }
+
+ fun testGenerateGetter() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ String y.;
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'Ge", ignoreCase = true) })
+ myFixture.checkResult("""
+ class A {
+ String y;
+
+ public String getY() {
+ return y;
+ }
+ }
+ """.trimIndent())
+ }
+
+ fun testDeleteLine() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ String y;
+
+ public String getY() {
+ return y;.
+ }
+ }""".trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Delete", ignoreCase = true) })
+ myFixture.checkResult("""
+ class A {
+ String y;
+
+ public String getY() {
+ }
+ }""".trimIndent())
+
+ }
+
+ fun testInline() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ public String getY() {
+ String y = "y";
+ return y.;
+ }
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Inline", ignoreCase = true) })
+ myFixture.checkResult("""
+ class A {
+ public String getY() {
+ return "y";
+ }
+ }
+ """.trimIndent())
+
+ }
+
+ fun testCommentElement() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ public String getY() {
+ return "y";
+ }
+ }.""".trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Comment element", ignoreCase = true) })
+ myFixture.checkResult("""
+ //class A {
+ // public String getY() {
+ // return "y";
+ // }
+ //}""".trimIndent())
+ }
+
+ fun testRename() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ void foo() {
+ String y. = "1";
+ System.out.println(y);
+ }
+ }""".trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Rename", ignoreCase = true) })
+ myFixture.type('\n')
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A {
+ void foo() {
+ String n
+ umber = "1";
+ System.out.println(number);
+ }
+ }""".trimIndent())
+ }
+
fun testCommandsOnlyGoToDeclaration() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -83,8 +267,43 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
""".trimIndent())
}
+ fun testCommandsOnlyGoToImplementation() {
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ interface A{
+
+ public void a.();
+
+ class B implements A{
+
+ @Override
+ public void a() {
+
+ }
+ }
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Go to impl", ignoreCase = true) })
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ interface A{
+
+ public void a();
+
+ class B implements A{
+
+ @Override
+ public void a() {
+
+ }
+ }
+ }
+ """.trimIndent())
+ }
+
fun testRedCode() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -106,7 +325,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testComment() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -128,7 +347,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testFlipIntention() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.configureByText(JavaFileType.INSTANCE, """
class A {
void foo() {
@@ -150,7 +369,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testInspection() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
myFixture.enableInspections(SizeReplaceableByIsEmptyInspection())
myFixture.configureByText(JavaFileType.INSTANCE, """
import java.util.List;
@@ -175,7 +394,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testBinaryNotAllowed() {
- Registry.get("java.completion.command.enabled").setValue(false, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(false, getTestRootDisposable())
val psiClass = JavaPsiFacade.getInstance(project).findClass(JAVA_LANG_CLASS, GlobalSearchScope.allScope(project))
val file = psiClass?.containingFile?.virtualFile
assertNotNull(file)
@@ -193,7 +412,7 @@ class JavaCommandsCompletionTest : LightFixtureCompletionTestCase() {
}
fun testBinaryNotAllowedCalledCompletion() {
- Registry.get("java.completion.command.enabled").setValue(true, getTestRootDisposable())
+ Registry.get("ide.completion.command.enabled").setValue(true, getTestRootDisposable())
val psiClass = JavaPsiFacade.getInstance(project).findClass(JAVA_LANG_CLASS, GlobalSearchScope.allScope(project))
val file = psiClass?.containingFile?.virtualFile
assertNotNull(file)
diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties
index d17f78c5a4bb..737417020af6 100644
--- a/java/openapi/resources/messages/JavaBundle.properties
+++ b/java/openapi/resources/messages/JavaBundle.properties
@@ -1956,11 +1956,7 @@ checkbox.check.for.jdk.updates=Check for JDK updates
intention.family.name.rename.to.ignored=Rename to ignored
tooltip.variable.used=Variable ''{0}'' is used
-command.completion.filter.hint=press '.' to show actions
-command.completion.generate.text=Generate ''{0}''
command.completion.inline.text=Inline
-command.completion.project.tool.text=Open Project tool window
-command.completion.recent.files.text=Open recent files popup
advanced.setting.java.show.irrelevant.templates.in.source.roots=Show irrelevant New File templates in Java source roots
java.test.use.wall.time=Use Wall Time
@@ -1971,6 +1967,5 @@ auto.test.on=Auto-test on
disable.auto.test=Disable auto-test
error.no.annotation.class.found=No annotation class found
-java.psi.element.comment.completion.command.text=Comment element
preview.api.usage={0} is a preview API and may be removed in a future release
preview.api.usage.reflective={0} is a reflective preview API and may be removed in a future release
diff --git a/platform/analysis-api/api-dump-experimental.txt b/platform/analysis-api/api-dump-experimental.txt
index c9df636a778e..44641f28d68b 100644
--- a/platform/analysis-api/api-dump-experimental.txt
+++ b/platform/analysis-api/api-dump-experimental.txt
@@ -1,3 +1,62 @@
+*a:com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+- com.intellij.codeInsight.completion.command.CompletionCommand
+- ():V
+- a:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- supportsReadOnly():Z
+*:com.intellij.codeInsight.completion.command.CommandCompletionFactory
+- 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
+- isApplicable(com.intellij.psi.PsiFile,I):Z
+- suffix():C
+*f:com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
+- (com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,Z):V
+- f:component1():com.intellij.openapi.project.Project
+- f:component2():com.intellij.openapi.editor.Editor
+- f:component3():I
+- f:component4():com.intellij.psi.PsiFile
+- f:component5():com.intellij.openapi.editor.Editor
+- f:component6():I
+- f:component7():com.intellij.psi.PsiFile
+- f:component8():Z
+- f:copy(com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,Z):com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
+- bs:copy$default(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext,com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor,I,com.intellij.psi.PsiFile,Z,I,java.lang.Object):com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
+- equals(java.lang.Object):Z
+- f:getEditor():com.intellij.openapi.editor.Editor
+- f:getOffset():I
+- f:getOriginalEditor():com.intellij.openapi.editor.Editor
+- f:getOriginalOffset():I
+- f:getOriginalPsiFile():com.intellij.psi.PsiFile
+- f:getProject():com.intellij.openapi.project.Project
+- f:getPsiFile():com.intellij.psi.PsiFile
+- hashCode():I
+- f:isReadOnly():Z
+*:com.intellij.codeInsight.completion.command.CommandProvider
+- a:getCommands(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):java.util.List
+- getId():java.lang.String
+- supportsReadOnly():Z
+*a:com.intellij.codeInsight.completion.command.CompletionCommand
+- ():V
+- a:execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
+- getAdditionalInfo():java.lang.String
+- getContext(I,com.intellij.psi.PsiFile):com.intellij.psi.PsiElement
+- getHighlightInfo():com.intellij.codeInsight.completion.command.HighlightInfoLookup
+- a:getI18nName():java.lang.String
+- a:getIcon():javax.swing.Icon
+- a:getName():java.lang.String
+- getPriority():java.lang.Integer
+*f:com.intellij.codeInsight.completion.command.HighlightInfoLookup
+- (com.intellij.openapi.util.TextRange,com.intellij.openapi.editor.colors.TextAttributesKey,I):V
+- f:component1():com.intellij.openapi.util.TextRange
+- f:component2():com.intellij.openapi.editor.colors.TextAttributesKey
+- f:component3():I
+- f:copy(com.intellij.openapi.util.TextRange,com.intellij.openapi.editor.colors.TextAttributesKey,I):com.intellij.codeInsight.completion.command.HighlightInfoLookup
+- bs:copy$default(com.intellij.codeInsight.completion.command.HighlightInfoLookup,com.intellij.openapi.util.TextRange,com.intellij.openapi.editor.colors.TextAttributesKey,I,I,java.lang.Object):com.intellij.codeInsight.completion.command.HighlightInfoLookup
+- equals(java.lang.Object):Z
+- f:getAttributesKey():com.intellij.openapi.editor.colors.TextAttributesKey
+- f:getPriority():I
+- f:getRange():com.intellij.openapi.util.TextRange
+- hashCode():I
*:com.intellij.codeInsight.completion.ml.MLRankingIgnorable
- s:wrap(com.intellij.codeInsight.lookup.LookupElement):com.intellij.codeInsight.lookup.LookupElement
*:com.intellij.codeInsight.highlighting.PsiHighlightedReference
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
new file mode 100644
index 000000000000..d14b895c8900
--- /dev/null
+++ b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandCompletionFactory.kt
@@ -0,0 +1,69 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
+
+import com.intellij.lang.Language
+import com.intellij.lang.LanguageExtension
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+
+/**
+ * Factory interface for creating and managing completion commands in a specific context.
+ *
+ * Provides functionality to determine applicability based on the file and offset,
+ * retrieve a list of command providers, and define suffixes used during code completion.
+ * Serves as a customization point for enhancing code completion workflows.
+ *
+ * Should implement DumbAware to support dumb mode
+ */
+@ApiStatus.Experimental
+interface CommandCompletionFactory {
+ /**
+ * Provides the default character suffix. After that, suffix command completion will be enabled
+ *
+ * @return The character suffix, which is '.'.
+ */
+ fun suffix(): Char = '.'
+
+ /**
+ * Determines the character suffix to filter only command lookup
+ */
+ fun filterSuffix(): Char? = '.'
+
+ /**
+ * Retrieves a list of command providers responsible for supplying completion commands.
+ * The default implementation returns a set of providers.
+ * Language plugins can add command providers via 'com.intellij.codeInsight.completion.command.provider' EP
+ * or implement [com.intellij.codeInsight.completion.command.ApplicableCompletionCommand]
+ * and register with 'com.intellij.codeInsight.completion.applicable.command' language extension
+ */
+ fun commandProviders(project: Project, language: Language): List {
+ if (!Registry.`is`("ide.completion.command.enabled")) return mutableListOf()
+ return DumbService.getInstance(project).filterByDumbAwareness(EP_NAME.allForLanguageOrAny(language))
+ }
+
+ /**
+ * Determines whether the functionality is applicable in the given context.
+ *
+ * @param psiFile the PSI file representing the file in which the applicability is being evaluated
+ * @param offset the position within the file where the applicability should be checked
+ * @return true if the functionality is applicable at the specified context, false otherwise
+ */
+ fun isApplicable(psiFile: PsiFile, offset: Int): Boolean {
+ return true
+ }
+
+ /**
+ * Creates a new file based on the provided original file and text content.
+ *
+ * @param originalFile The base file from which the new file will be created. It must be of type `PsiFile`.
+ * @param text The text content to be used for the newly created file.
+ * @return new file, containing text or null if creation file with [com.intellij.psi.PsiFileFactory.createFileFromText] is available
+ *
+ */
+ fun createFile(originalFile: PsiFile, text: String): PsiFile? = null
+}
+
+private val EP_NAME = LanguageExtension("com.intellij.codeInsight.completion.command.provider")
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandProvider.kt b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandProvider.kt
similarity index 90%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandProvider.kt
rename to platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandProvider.kt
index 2c864db21124..e06c24e88456 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CommandProvider.kt
+++ b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CommandProvider.kt
@@ -1,8 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.api
+package com.intellij.codeInsight.completion.command
import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.ApiStatus.Experimental
@@ -16,9 +15,6 @@ import org.jetbrains.annotations.ApiStatus.Experimental
*/
@Experimental
interface CommandProvider {
- companion object {
- val EP_NAME = ExtensionPointName("com.intellij.codeInsight.completion.command.provider")
- }
/**
@@ -31,7 +27,7 @@ interface CommandProvider {
*/
fun getCommands(context: CommandCompletionProviderContext): List
- fun getId(): String
+ fun getId(): String = javaClass.name
/**
* Indicates whether the implementation supports non-written files.
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CompletionCommand.kt
similarity index 61%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt
rename to platform/analysis-api/src/com/intellij/codeInsight/completion/command/CompletionCommand.kt
index 27a4f0eeb4c7..add86b39574e 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/api/CompletionCommand.kt
+++ b/platform/analysis-api/src/com/intellij/codeInsight/completion/command/CompletionCommand.kt
@@ -1,15 +1,9 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.api
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
-import com.intellij.codeInsight.TargetElementUtil
-import com.intellij.codeInsight.completion.commands.core.HighlightInfoLookup
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.actionSystem.DataContext
-import com.intellij.openapi.actionSystem.LangDataKeys
-import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.extensions.ExtensionPointName
-import com.intellij.openapi.project.IndexNotReadyException
+import com.intellij.openapi.editor.colors.TextAttributesKey
+import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.util.concurrency.annotations.RequiresEdt
@@ -87,10 +81,6 @@ abstract class CompletionCommand {
*/
@ApiStatus.Experimental
abstract class ApplicableCompletionCommand : CompletionCommand() {
- companion object {
-
- val EP_NAME = ExtensionPointName("com.intellij.codeInsight.completion.command")
- }
/**
* Determines whether the command is applicable based on the given context.
@@ -112,47 +102,9 @@ abstract class ApplicableCompletionCommand : CompletionCommand() {
open fun supportsReadOnly(): Boolean = false
}
-/**
- * Constructs a [DataContext] instance using the specified parameters, including the PSI file,
- * editor, and optionally a context element. The resulting data context is populated with
- * relevant keys and values to be used within the context of the provided elements.
- *
- * @param psiFile The [PsiFile] associated with the current context.
- * @param editor The [Editor] instance corresponding to the current context.
- * @param context An optional [PsiElement] representing the context; can be null.
- * @return A [DataContext] instance containing the provided context information.
- */
-internal fun getDataContext(
- psiFile: PsiFile,
- editor: Editor,
- context: PsiElement?,
-): DataContext {
- val dataContext = SimpleDataContext.builder()
- .add(CommonDataKeys.PROJECT, psiFile.project)
- .add(CommonDataKeys.EDITOR, editor)
- .add(CommonDataKeys.PSI_ELEMENT, context)
- .add(CommonDataKeys.PSI_FILE, psiFile)
- .add(LangDataKeys.CONTEXT_LANGUAGES, arrayOf(psiFile.language))
- .build()
- return dataContext
-}
-
-/**
- * Retrieves the PSI element located at the specified offset within the editor's context.
- * This method attempts to find a target PSI element based on the editor's state and the offset,
- * allowing interaction with the underlying code structure.
- *
- * @param offset The offset in the editor's document where the target element is to be located.
- * @param editor The editor instance in which the method searches for the target element.
- * @return The PSI element found at the specified offset, or null if no suitable element is found
- * or if the index is not ready.
- */
-internal fun getTargetContext(offset: Int, editor: Editor): PsiElement? {
- try {
- val util = TargetElementUtil.getInstance()
- return util.findTargetElement(editor, util.getReferenceSearchFlags(), offset)
- }
- catch (_: IndexNotReadyException) {
- return null
- }
-}
\ No newline at end of file
+@ApiStatus.Experimental
+data class HighlightInfoLookup(
+ val range: TextRange,
+ val attributesKey: TextAttributesKey,
+ val priority: Int, //higher is on the top
+)
diff --git a/platform/lang-api/resources/messages/CodeInsightBundle.properties b/platform/lang-api/resources/messages/CodeInsightBundle.properties
index 82aa3d77decd..109330c7ed7c 100644
--- a/platform/lang-api/resources/messages/CodeInsightBundle.properties
+++ b/platform/lang-api/resources/messages/CodeInsightBundle.properties
@@ -607,3 +607,8 @@ jvm.inspections.dependency.configure.button.text=Configure dependency rules
checking.code.highlightings.in.background=Loading Code Highlighting
title.checking.code.highlightings.in.background.task=Loading code passes
documentation.download.button.label=Download documentation
+command.completion.filter.hint=press ''{0}'' to show actions
+command.completion.project.tool.text=Open Project tool window
+command.completion.recent.files.text=Open recent files popup
+command.completion.generate.text=Generate ''{0}''
+command.completion.psi.element.comment.text=Comment element
\ No newline at end of file
diff --git a/platform/lang-impl/api-dump-experimental.txt b/platform/lang-impl/api-dump-experimental.txt
index 89f1d0100e87..2038203cdf5d 100644
--- a/platform/lang-impl/api-dump-experimental.txt
+++ b/platform/lang-impl/api-dump-experimental.txt
@@ -143,6 +143,95 @@ c:com.intellij.codeInsight.actions.VcsFacade
*f:com.intellij.codeInsight.codeVision.CodeVisionProvider$Companion
- sf:EP_NAME:java.lang.String
- f:getProvidersExtensionPoint():com.intellij.openapi.extensions.ExtensionPointName
+*a:com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+- com.intellij.openapi.project.DumbAware
+- (java.lang.String,java.lang.String,java.lang.String,javax.swing.Icon,java.lang.Integer):V
+- b:(java.lang.String,java.lang.String,java.lang.String,javax.swing.Icon,java.lang.Integer,I,kotlin.jvm.internal.DefaultConstructorMarker):V
+- execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
+- f:getActionId():java.lang.String
+- getAdditionalInfo():java.lang.String
+- getI18nName():java.lang.String
+- getIcon():javax.swing.Icon
+- getName():java.lang.String
+- getPriority():java.lang.Integer
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- pf:isApplicableToProject(I,com.intellij.psi.PsiFile):Z
+- f:setActionId(java.lang.String):V
+*a:com.intellij.codeInsight.completion.command.commands.AbstractCopyFQNCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- f:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- a:placeIsApplicable(com.intellij.psi.PsiElement,I):Z
+- f:supportsReadOnly():Z
+*a:com.intellij.codeInsight.completion.command.commands.AbstractFormatCodeCompletionCommand
+- com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+- ():V
+- f:execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
+- a:findTargetToRefactor(com.intellij.psi.PsiElement):com.intellij.psi.PsiElement
+- f:getI18nName():java.lang.String
+- f:getIcon():javax.swing.Icon
+- f:getName():java.lang.String
+- f:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+*a:com.intellij.codeInsight.completion.command.commands.AbstractGenerateCommandProvider
+- com.intellij.codeInsight.completion.command.CommandProvider
+- com.intellij.openapi.project.DumbAware
+- ():V
+- a:generationIsAvailable(com.intellij.psi.PsiElement,I):Z
+- f:getCommands(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):java.util.List
+- pf:isOnlySpaceInLine(com.intellij.openapi.editor.Document,I):Z
+*a:com.intellij.codeInsight.completion.command.commands.AbstractGoToDeclarationCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- a:canNavigateToDeclaration(com.intellij.psi.PsiElement):Z
+- f:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- f:supportsReadOnly():Z
+*a:com.intellij.codeInsight.completion.command.commands.AbstractGoToImplementationCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- a:canGoToImplementation(com.intellij.psi.PsiElement,I):Z
+- f:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- f:supportsReadOnly():Z
+*a:com.intellij.codeInsight.completion.command.commands.AbstractShowUsagesActionCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- a:hasToShow(com.intellij.psi.PsiElement):Z
+- f:isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- f:supportsReadOnly():Z
+*f:com.intellij.codeInsight.completion.command.commands.DirectIntentionCommandProvider
+- com.intellij.codeInsight.completion.command.CommandProvider
+- ():V
+- getCommands(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):java.util.List
+*:com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper
+- *sf:Companion:com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper$Companion
+- skip(com.intellij.codeInsight.intention.CommonIntentionAction,com.intellij.psi.PsiFile,I):Z
+*f:com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper$Companion
+*f:com.intellij.codeInsight.completion.command.commands.LineCommentCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
+*f:com.intellij.codeInsight.completion.command.commands.OptimizeImportCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+*f:com.intellij.codeInsight.completion.command.commands.ProjectViewCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- supportsReadOnly():Z
+*f:com.intellij.codeInsight.completion.command.commands.RecentFilesCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+- supportsReadOnly():Z
+*f:com.intellij.codeInsight.completion.command.commands.RenameActionCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
+*f:com.intellij.codeInsight.completion.command.commands.SimpleRunMarkerCommandProvider
+- com.intellij.codeInsight.completion.command.CommandProvider
+- ():V
+- getCommands(com.intellij.codeInsight.completion.command.CommandCompletionProviderContext):java.util.List
*:com.intellij.codeInsight.daemon.impl.focusMode.FocusModeProvider
- a:calcFocusZones(com.intellij.psi.PsiFile):java.util.List
*:com.intellij.codeInsight.editorActions.TypingActionsExtension
diff --git a/platform/lang-impl/api-dump-unreviewed.txt b/platform/lang-impl/api-dump-unreviewed.txt
index 6393834394b6..dcc14a1c88e2 100644
--- a/platform/lang-impl/api-dump-unreviewed.txt
+++ b/platform/lang-impl/api-dump-unreviewed.txt
@@ -2133,6 +2133,11 @@ f:com.intellij.codeInsight.completion.addingPolicy.PassDirectlyPolicy
- ():V
- addAllElements(com.intellij.codeInsight.completion.CompletionResultSet,java.lang.Iterable):V
- addElement(com.intellij.codeInsight.completion.CompletionResultSet,com.intellij.codeInsight.lookup.LookupElement):V
+f:com.intellij.codeInsight.completion.command.commands.PsiElementCommentCompletionCommand
+- com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+- ():V
+- execute(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):V
+- isApplicable(I,com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor):Z
c:com.intellij.codeInsight.completion.impl.BetterPrefixMatcher
- com.intellij.codeInsight.completion.PrefixMatcher
- (com.intellij.codeInsight.completion.PrefixMatcher,I):V
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/AbstractActionCompletionCommand.kt
similarity index 60%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/AbstractActionCompletionCommand.kt
index 67cdbf37aa05..28daf3f63472 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/AbstractActionCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/AbstractActionCompletionCommand.kt
@@ -1,9 +1,6 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
-import com.intellij.codeInsight.completion.commands.api.ApplicableCompletionCommand
-import com.intellij.codeInsight.completion.commands.api.getDataContext
-import com.intellij.codeInsight.completion.commands.api.getTargetContext
import com.intellij.ide.DataManager
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ex.ActionUtil
@@ -13,9 +10,17 @@ import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.DumbService
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Icon
+/**
+ * Represents an abstract action completion command that triggers a specific IDE action
+ * identified by its `actionId`. This class allows integration of IntelliJ Platform actions
+ * as part of code completion features, ensuring that the action is applicable and
+ * executable within a given code editor context.
+ */
+@ApiStatus.Experimental
abstract class AbstractActionCompletionCommand(
var actionId: String,
override val name: String,
@@ -37,11 +42,11 @@ abstract class AbstractActionCompletionCommand(
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
val action = action ?: return false
if (editor == null) return false
- if (!DumbService.getInstance(psiFile.project).isUsableInCurrentContext(action)) return false
+ if (!DumbService.Companion.getInstance(psiFile.project).isUsableInCurrentContext(action)) return false
val context = getTargetContext(offset, editor)
val dataContext = getDataContext(psiFile, editor, context)
val presentation: Presentation = action.templatePresentation.clone()
- val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
+ val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.Companion.NONE, null)
if (ActionUtil.performDumbAwareUpdate(action, event, false)) {
return false
}
@@ -53,20 +58,28 @@ abstract class AbstractActionCompletionCommand(
if (editor == null) return
val dataContext = DataManager.getInstance().getDataContext(editor.getComponent())
val presentation: Presentation = action.templatePresentation.clone()
- val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.NONE, null)
+ val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, ActionUiKind.Companion.NONE, null)
if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
ActionUtil.performActionDumbAwareWithCallbacks(action, event)
}
}
- companion object {
- internal fun isApplicableToProject(offset: Int, psiFile: PsiFile): Boolean {
- if (offset - 1 < 0) return true
- val element = psiFile.findElementAt(offset - 1)
- if (element is PsiComment) return true
- val ch = psiFile.fileDocument.immutableCharSequence[offset - 1]
- if (!ch.isLetterOrDigit() && ch != ']' && ch != ')') return true
- return false
+ /**
+ * Determines if the action associated with this command can be applied to the given project context
+ * by analyzing the specified offset and the PsiFile structure.
+ * It is expected to be called outside any meaningful PsiElements
+ */
+ protected fun isApplicableToProject(offset: Int, psiFile: PsiFile): Boolean {
+ if (offset - 1 < 0) return true
+ val element = psiFile.findElementAt(offset - 1)
+ if (element is PsiComment) return true
+ val fileDocument = psiFile.fileDocument
+ val lineNumber = fileDocument.getLineNumber(offset)
+ val lineStartOffset = fileDocument.getLineStartOffset(lineNumber)
+ for (ch in fileDocument.immutableCharSequence.subSequence(lineStartOffset, offset)) {
+ if (!ch.isWhitespace()) return false
+ if (ch == '\n') return true
}
+ return true
}
}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/ApplicationCommandCompletionService.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/ApplicationCommandCompletionService.kt
similarity index 72%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/core/ApplicationCommandCompletionService.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/ApplicationCommandCompletionService.kt
index cd3a3441c492..70b6dea7ab24 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/ApplicationCommandCompletionService.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/ApplicationCommandCompletionService.kt
@@ -1,10 +1,14 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
import com.intellij.openapi.components.*
import org.jetbrains.annotations.ApiStatus
+/**
+ * Service responsible for managing and persisting command completion settings at the application level.
+ *
+ */
@Service(Service.Level.APP)
@ApiStatus.Experimental
@ApiStatus.Internal
@@ -20,6 +24,8 @@ class ApplicationCommandCompletionService : PersistentStateComponent(lookupElement) {
+ override fun isWorthShowingInAutoPopup(): Boolean {
+ return true
+ }
+
+ override fun getAutoCompletionPolicy(): AutoCompletionPolicy? {
+ return NEVER_AUTOCOMPLETE
+ }
+}
+
+
+/**
+ * Constructs a [DataContext] instance using the specified parameters, including the PSI file,
+ * editor, and optionally a context element. The resulting data context is populated with
+ * relevant keys and values to be used within the context of the provided elements.
+ *
+ * @param psiFile The [PsiFile] associated with the current context.
+ * @param editor The [Editor] instance corresponding to the current context.
+ * @param context An optional [PsiElement] representing the context; can be null.
+ * @return A [DataContext] instance containing the provided context information.
+ */
+@Internal
+@Experimental
+fun getDataContext(
+ psiFile: PsiFile,
+ editor: Editor,
+ context: PsiElement?,
+): DataContext {
+ val dataContext = SimpleDataContext.builder()
+ .add(CommonDataKeys.PROJECT, psiFile.project)
+ .add(CommonDataKeys.EDITOR, editor)
+ .add(CommonDataKeys.PSI_ELEMENT, context)
+ .add(CommonDataKeys.PSI_FILE, psiFile)
+ .add(LangDataKeys.CONTEXT_LANGUAGES, arrayOf(psiFile.language))
+ .build()
+ return dataContext
+}
+
+/**
+ * Retrieves the PSI element located at the specified offset within the editor's context.
+ * This method attempts to find a target PSI element based on the editor's state and the offset,
+ * allowing interaction with the underlying code structure.
+ *
+ * @param offset The offset in the editor's document where the target element is to be located.
+ * @param editor The editor instance in which the method searches for the target element.
+ * @return The PSI element found at the specified offset, or null if no suitable element is found
+ * or if the index is not ready.
+ */
+@Internal
+@Experimental
+fun getTargetContext(offset: Int, editor: Editor): PsiElement? {
+ try {
+ val util = TargetElementUtil.getInstance()
+ return util.findTargetElement(editor, util.getReferenceSearchFlags(), offset)
+ }
+ catch (_: IndexNotReadyException) {
+ return null
+ }
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionNonWriteAccessTypedHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionNonWriteAccessTypedHandler.kt
similarity index 88%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionNonWriteAccessTypedHandler.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionNonWriteAccessTypedHandler.kt
index 60373fa419c6..b9775f3d1869 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionNonWriteAccessTypedHandler.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionNonWriteAccessTypedHandler.kt
@@ -1,5 +1,5 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase
import com.intellij.codeInsight.completion.CompletionType
@@ -20,7 +20,7 @@ import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.registry.Registry.Companion.`is`
+import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.wm.IdeFocusManager
import com.intellij.psi.PsiDocumentManager
@@ -32,9 +32,17 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.jetbrains.annotations.ApiStatus
+/**
+ * Handles non-write access typed events for command-based code completion functionality.
+ * This class extends the `NonWriteAccessTypedHandler` to provide custom behavior for handling typed characters
+ * and triggering command completions without modifying the editor's document directly.
+ *
+ */
+@ApiStatus.Experimental
+@ApiStatus.Internal
class CommandCompletionNonWriteAccessTypedHandler : NonWriteAccessTypedHandler {
override fun isApplicable(editor: Editor, charTyped: Char, dataContext: DataContext): Boolean {
- if (!`is`("java.completion.command.enabled")) return false
+ if (!Registry.`is`("ide.completion.command.enabled")) return false
val project = editor.project ?: return false
val commandCompletionService = project.getService(CommandCompletionService::class.java)
if (commandCompletionService == null) return false
@@ -56,7 +64,7 @@ class CommandCompletionNonWriteAccessTypedHandler : NonWriteAccessTypedHandler {
}
override fun handle(editor: Editor, charTyped: Char, dataContext: DataContext) {
- if (!`is`("java.completion.command.enabled")) return
+ if (!Registry.`is`("ide.completion.command.enabled")) return
val accessCommandCompletionService = editor.project?.getService(NonWriteAccessCommandCompletionService::class.java)
if (accessCommandCompletionService == null) return
accessCommandCompletionService.insertNewEditor(editor)
@@ -70,12 +78,11 @@ internal val ORIGINAL_EDITOR = Key.create>("completion.command
@ApiStatus.Experimental
@Service(Service.Level.PROJECT)
class NonWriteAccessCommandCompletionService(
- private val project: Project,
val coroutineScope: CoroutineScope,
) {
fun insertNewEditor(editor: Editor) {
- if (!`is`("java.completion.command.enabled")) return
+ if (!Registry.`is`("ide.completion.command.enabled")) return
if (editor !is EditorImpl) return
val project = editor.project ?: return
val offset = editor.caretModel.offset
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionProvider.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionProvider.kt
similarity index 74%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionProvider.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionProvider.kt
index 439cf04ed5cc..827ae639db99 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionProvider.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionProvider.kt
@@ -1,10 +1,7 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
import com.intellij.codeInsight.completion.*
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionFactory
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionProviderContext
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
import com.intellij.codeInsight.completion.ml.MLWeigherUtil
import com.intellij.codeInsight.lookup.LookupElement
@@ -36,6 +33,15 @@ import com.intellij.util.ProcessingContext
import com.intellij.util.Processor
import org.jetbrains.annotations.ApiStatus
+/**
+ * Internal provider for handling command completion in IntelliJ-based editors.
+ *
+ * This class extends the `CompletionProvider` to provide custom completion suggestions
+ * in contexts where command completions are applicable. It is primarily used for adding
+ * completions for specific command-based scenarios in supported languages or files.
+ *
+ */
+@ApiStatus.Internal
@ApiStatus.Experimental
internal class CommandCompletionProvider : CompletionProvider() {
@@ -48,7 +54,7 @@ internal class CommandCompletionProvider : CompletionProvider("add filter for command completion") {
- override fun accepts(t: String, context: ProcessingContext?): Boolean {
- return !isReadOnly && commandCompletionType.suffix.toString() + t ==
- commandCompletionFactory.suffix() + commandCompletionFactory.filterSuffix().toString() ||
- isReadOnly && commandCompletionType.suffix.toString() + t == commandCompletionFactory.filterSuffix().toString()
- }
- }))
+ withPrefixMatcher.restartCompletionOnPrefixChange(
+ StandardPatterns.string().with(object : PatternCondition("add filter for command completion") {
+ override fun accepts(t: String, context: ProcessingContext?): Boolean {
+ return !isReadOnly && commandCompletionType.suffix + t ==
+ commandCompletionFactory.suffix() + commandCompletionFactory.filterSuffix().toString() ||
+ isReadOnly && commandCompletionType.suffix.toString() + t == commandCompletionFactory.filterSuffix().toString()
+ }
+ }))
// Fetch commands applicable to the position
processCommandsForContext(commandCompletionFactory,
@@ -179,13 +188,24 @@ internal class CommandCompletionProvider : CompletionProvider 0 && text.substring(offset - indexOf, offset - indexOf + 2).contains(factory.suffix())) {
+ //force call with one point
+ return InvocationCommandType.PartialSuffix(text.substring(offset - indexOf + 1, offset),
+ text.substring(offset - indexOf, offset - indexOf + 1))
+ }
+ if (!Registry.`is`("ide.completion.command.full.line.enabled")) return null
if (indexOf > 0) {
- return InvocationCommandType.PartialSuffix(text.substring(offset - indexOf + 1, offset), text.substring(offset - indexOf, offset - indexOf + 1))
+ //full empty line
+ return InvocationCommandType.FullLine(text.substring(offset - indexOf, offset), "")
}
return null
}
@@ -204,10 +224,11 @@ internal class CommandCompletionProvider : CompletionProvider= 0 && (text[offset - currentIndex].isLetter() ||
+ text[offset - currentIndex] == ' ' ||
+ text[offset - currentIndex] == '\'')
+ ) {
+ currentIndex++
+ }
+ if (currentIndex <= 1 || text[offset - currentIndex] != '\n') return indexOf
+ while (currentIndex >= 0 && text[offset - currentIndex].isWhitespace()) {
+ currentIndex--
+ }
+ if (currentIndex >= 0) indexOf = currentIndex
+ }
return indexOf
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionService.kt
similarity index 90%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionService.kt
index f2c756a75395..25734a234132 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandCompletionService.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandCompletionService.kt
@@ -1,7 +1,7 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionFactory
+import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.daemon.impl.HintRenderer
import com.intellij.codeInsight.editorLineStripeHint.EditorLineStripeTextRenderer
import com.intellij.codeInsight.highlighting.HighlightManager
@@ -12,7 +12,6 @@ import com.intellij.codeInsight.lookup.CharFilter.CUSTOM_DEFAULT_CHAR_FILTERS
import com.intellij.codeInsight.lookup.impl.LookupCustomizer
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.template.impl.TemplateColors
-import com.intellij.java.JavaBundle
import com.intellij.lang.Language
import com.intellij.lang.LanguageExtension
import com.intellij.lang.injection.InjectedLanguageManager
@@ -29,7 +28,6 @@ import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.editor.markup.HighlighterLayer
import com.intellij.openapi.editor.markup.HighlighterTargetArea
import com.intellij.openapi.editor.markup.RangeHighlighter
-import com.intellij.openapi.project.Project
import com.intellij.openapi.util.*
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiDocumentManager
@@ -43,11 +41,17 @@ import org.jetbrains.annotations.ApiStatus
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.min
+/**
+ * Service class responsible for managing and providing functionality for command completion within a project.
+ *
+ * This class allows filtering and enhancing the behavior of code completion for commands, assisting in the
+ * integration of additional matchers, hint rendering, and custom lookup arrangements. It relies on language-specific
+ * completion factories to customize behavior according to individual requirements.
+ */
@ApiStatus.Internal
@ApiStatus.Experimental
@Service(Service.Level.PROJECT)
internal class CommandCompletionService(
- private val project: Project,
val coroutineScope: CoroutineScope,
) : Disposable {
@@ -126,7 +130,7 @@ internal class CommandCompletionService(
val state = applicationCommandCompletionService.state
if (state.showCounts > 5) return
state.showCounts += 1
- val inlineElement: Inlay = editor.inlayModel.addInlineElement(endOffset, true, EditorLineStripeTextRenderer(" " + JavaBundle.message("command.completion.filter.hint")))
+ val inlineElement: Inlay = editor.inlayModel.addInlineElement(endOffset, true, EditorLineStripeTextRenderer(" " + CodeInsightBundle.message("command.completion.filter.hint", completionFactory.filterSuffix())))
?: return
Disposer.register(lookup, inlineElement)
Disposer.register(lookup) { lookup.removeUserData(INSTALLED_HINT) }
@@ -156,7 +160,7 @@ private const val PROMPT_LAYER = HighlighterLayer.ERROR + 10
private class CommandCompletionListener : LookupManagerListener {
override fun activeLookupChanged(oldLookup: Lookup?, newLookup: Lookup?) {
- if (!Registry.`is`("java.completion.command.enabled")) return
+ if (!Registry.`is`("ide.completion.command.enabled")) return
var editor = newLookup?.editor ?: return
val originalEditor = editor.getUserData(ORIGINAL_EDITOR)
var psiFile = newLookup.psiFile ?: return
@@ -253,7 +257,8 @@ private class CommandCompletionHighlightingListener(
private fun update(lookup: LookupImpl, item: CommandCompletionLookupElement) {
val installed = ConcurrencyUtil.computeIfAbsent(lookup, INSTALLED_LISTENER_KEY) { AtomicBoolean(false) }
- val startOffset = lookup.lookupOriginalStart - findActualIndex(item.suffix, editor.document.immutableCharSequence, lookup.lookupOriginalStart)
+ val startOffset = lookup.lookupOriginalStart - findActualIndex(item.suffix, editor.document.immutableCharSequence,
+ lookup.lookupOriginalStart)
val lookupEditor = InjectedLanguageEditorUtil.getTopLevelEditor(lookup.editor)
val endOffset = lookupEditor.caretModel.offset
if (!installed.get()) {
@@ -295,7 +300,9 @@ private class CommandCompletionHighlightingListener(
val previousHighlighting = lookup.removeUserData(LOOKUP_HIGHLIGHTING)
previousHighlighting?.forEach { t -> highlightManager.removeSegmentHighlighter(editor, t) }
val startOffset = lookup.lookupOriginalStart -
- if (nonWrittenFiles) 0 else findActualIndex(element.suffix, editor.document.immutableCharSequence, lookup.lookupOriginalStart)
+ if (nonWrittenFiles) 0
+ else findActualIndex(element.suffix, editor.document.immutableCharSequence,
+ lookup.lookupOriginalStart)
val highlightInfo = element.highlighting ?: return
val rangeHighlighters = mutableListOf()
val endOffset = min(highlightInfo.range.endOffset, startOffset)
@@ -323,9 +330,17 @@ private class CommandCompletionHighlightingListener(
}
}
+/**
+ * A custom implementation of [CharFilter] that provides specific behavior for handling character inputs
+ * during completion, particularly for commands.
+ * This implementation works in conjunction with the `CommandCompletionService`.
+ * This filter evaluates whether a given character should modify the current completion prefix,
+ * select an item, or hide the lookup based on various conditions, such as the presence of
+ * specific data in the current lookup or the state of the caret/editor.
+ */
private class CommandCompletionCharFilter : CharFilter() {
override fun acceptChar(c: Char, prefixLength: Int, lookup: Lookup?): Result? {
- if (!Registry.`is`("java.completion.command.enabled")) return null
+ if (!Registry.`is`("ide.completion.command.enabled")) return null
if (lookup !is LookupImpl) return null
val completionService = lookup.project.service()
val installedHint = lookup.removeUserData(INSTALLED_HINT)
@@ -351,9 +366,13 @@ private class CommandCompletionCharFilter : CharFilter() {
}
}
+/**
+ * A private implementation of the `LookupCustomizer` interface that modifies a lookup instance
+ * to insert additional flags.
+ */
private class CommandCompletionLookupCustomizer : LookupCustomizer {
override fun customizeLookup(lookupImpl: LookupImpl) {
- if (!Registry.`is`("java.completion.command.enabled")) return
+ if (!Registry.`is`("ide.completion.command.enabled")) return
val project = lookupImpl.project
val service = project.service()
val editor = lookupImpl.editor
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandInsertHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandInsertHandler.kt
similarity index 90%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandInsertHandler.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandInsertHandler.kt
index d630a7842e1d..97ebdebfd2b6 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/core/CommandInsertHandler.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/CommandInsertHandler.kt
@@ -1,9 +1,8 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.core
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command
import com.intellij.codeInsight.completion.InsertHandler
import com.intellij.codeInsight.completion.InsertionContext
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.injected.editor.DocumentWindow
import com.intellij.lang.injection.InjectedLanguageManager
@@ -17,12 +16,18 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
import org.jetbrains.annotations.ApiStatus
+/**
+ * A handler for managing the insertion of commands during code completion.
+ * This class manages specific behaviors that occur when a command from the lookup
+ * list is selected and inserted into the editor.
+ */
+@ApiStatus.Internal
@ApiStatus.Experimental
internal class CommandInsertHandler(private val completionCommand: CompletionCommand) : InsertHandler {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
var editor = context.editor
val originalEditor = editor.getUserData(ORIGINAL_EDITOR)
- var startOffset = 0
+ var startOffset: Int
var psiFile = context.file
if (originalEditor != null) {
startOffset = originalEditor.second
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractCopyFQNCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractCopyFQNCompletionCommand.kt
new file mode 100644
index 000000000000..11edd19b1331
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractCopyFQNCompletionCommand.kt
@@ -0,0 +1,39 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+import com.intellij.ide.IdeBundle
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+
+/**
+ * Represents an abstract command for copying Fully Qualified Names (FQN) as part of the code completion process.
+ * This command provides functionality to determine its applicability based on a specific element within the PSI
+ * file and the current editor context.
+ */
+@ApiStatus.Experimental
+abstract class AbstractCopyFQNCompletionCommand : AbstractActionCompletionCommand("CopyReference",
+ "Copy Reference",
+ IdeBundle.message("copy.reference"),
+ null,
+ -150) {
+ final override fun supportsReadOnly(): Boolean = true
+
+ final override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ if (!super.isApplicable(offset, psiFile, editor)) return false
+ val element = getContext(offset, psiFile)
+ if (element == null) return false
+ return placeIsApplicable(element, offset)
+ }
+
+ /**
+ * Determines whether a specific context within a PSI element is applicable for the command execution.
+ *
+ * @param element The PSI element to evaluate, or null if no context is applicable.
+ * @param offset The position in the document where the applicability is being checked.
+ * @return true if the place is applicable based on the provided element and offset, false otherwise.
+ */
+ abstract fun placeIsApplicable(element: PsiElement, offset: Int): Boolean
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractFormatCodeCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractFormatCodeCompletionCommand.kt
new file mode 100644
index 000000000000..262996571717
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractFormatCodeCompletionCommand.kt
@@ -0,0 +1,47 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.actions.ReformatCodeProcessor
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+import com.intellij.icons.AllIcons
+import com.intellij.idea.ActionsBundle
+import com.intellij.lang.injection.InjectedLanguageManager
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+import org.jetbrains.annotations.Nls
+import javax.swing.Icon
+
+/**
+ * An abstract command designed to provide a context-specific code formatting completion action.
+ * This class handles the completion logic for reformatting code based on the PSI (Program Structure Interface)
+ * context and specific applicability conditions.
+ */
+@ApiStatus.Experimental
+abstract class AbstractFormatCodeCompletionCommand : ApplicableCompletionCommand() {
+ final override val name: String
+ get() = "Format"
+
+ final override val i18nName: @Nls String
+ get() = ActionsBundle.message("action.ReformatCode.text")
+
+ final override val icon: Icon
+ get() = AllIcons.Actions.ReformatCode // Use the reformat icon
+
+ final override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ if (InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)) return false
+ return true
+ }
+
+ final override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ val element = getContext(offset, psiFile) ?: return
+ val target = findTargetToRefactor(element)
+ ReformatCodeProcessor(element.containingFile, arrayOf(target.textRange)).run()
+ }
+
+ /**
+ * Finds the appropriate parent element for refactoring based on the given PSI element.
+ */
+ abstract fun findTargetToRefactor(element: PsiElement): PsiElement
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGenerateCommandProvider.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGenerateCommandProvider.kt
new file mode 100644
index 000000000000..84646c3b0aa6
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGenerateCommandProvider.kt
@@ -0,0 +1,97 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.CodeInsightBundle
+import com.intellij.codeInsight.actions.CodeInsightAction
+import com.intellij.codeInsight.completion.command.*
+import com.intellij.ide.DataManager
+import com.intellij.lang.injection.InjectedLanguageManager
+import com.intellij.openapi.actionSystem.*
+import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.actionSystem.impl.Utils
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.project.DumbService
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.util.containers.JBIterable
+import org.jetbrains.annotations.ApiStatus.Experimental
+import org.jetbrains.annotations.Nls
+import javax.swing.Icon
+
+/**
+ * Abstract base class that provides a framework for generating completion commands
+ * in a code completion system.
+ */
+@Experimental
+abstract class AbstractGenerateCommandProvider : CommandProvider, DumbAware {
+ final override fun getCommands(context: CommandCompletionProviderContext): List {
+ val psiFile = context.psiFile
+ val project = context.project
+ val offset = context.offset
+ val editor = context.editor
+ if (InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)) return emptyList()
+ val element = psiFile.findElementAt(if (offset - 1 >= 0) offset - 1 else offset)
+ if (element == null) return emptyList()
+ if (!generationIsAvailable(element, offset)) return emptyList()
+ val context = getTargetContext(offset, editor)
+ val dataContext = getDataContext(psiFile, editor, context)
+ val actionEvent = AnActionEvent.createEvent(dataContext, null, ActionPlaces.UNKNOWN, ActionUiKind.Companion.NONE, null)
+ actionEvent.updateSession = UpdateSession.EMPTY
+ Utils.initUpdateSession(actionEvent)
+ val generateActions: MutableList = ArrayList()
+ val session = actionEvent.updateSession
+ val dumbService = DumbService.Companion.getInstance(project)
+ val activeActions = JBIterable.from(
+ session.expandedChildren(ActionManager.getInstance().getAction(IdeActions.GROUP_GENERATE) as ActionGroup))
+ .filter { dumbService.isUsableInCurrentContext(it) }
+ .filter { o: AnAction? -> o !is Separator && o != null && session.presentation(o).isEnabledAndVisible }
+ for (action in activeActions) {
+ if (action is CodeInsightAction) {
+ generateActions.add(action)
+ }
+ }
+ return generateActions.map { GenerateCompletionCommand(it) }
+ }
+
+ protected fun isOnlySpaceInLine(document: Document, offset: Int): Boolean {
+ val lineNumber = document.getLineNumber(offset)
+ val lineStartOffset = document.getLineStartOffset(lineNumber)
+ val immutableCharSequence = document.immutableCharSequence
+ for (i in lineStartOffset..offset) {
+ if (!immutableCharSequence[i].isWhitespace()) {
+ return false
+ }
+ }
+ return true
+ }
+
+ /**
+ * Determines if generation actions are available for the provided PSI element.
+ *
+ * @param element A PSI element for which the availability of generation actions is to be checked.
+ * @param offset A current offset.
+ * @return `true` if generation actions are available for the specified element; `false` otherwise.
+ */
+ abstract fun generationIsAvailable(element: PsiElement, offset: Int): Boolean
+}
+
+internal class GenerateCompletionCommand(private val action: CodeInsightAction) : CompletionCommand() {
+ override val name: String
+ get() = "Generate \'" + action.templateText + "\'"
+ override val i18nName: @Nls String
+ get() = CodeInsightBundle.message("command.completion.generate.text", action.templateText)
+ override val icon: Icon?
+ get() = null
+
+ override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ if (editor == null) return
+ val dataContext = DataManager.getInstance().getDataContext(editor.getComponent())
+ val presentation: Presentation = action.templatePresentation.clone()
+ val event = AnActionEvent.createEvent(action, dataContext, presentation, ActionPlaces.UNKNOWN, ActionUiKind.NONE, null)
+ if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) {
+ ActionUtil.performActionDumbAwareWithCallbacks(action, event)
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToDeclarationCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToDeclarationCompletionCommand.kt
new file mode 100644
index 000000000000..00e0bf75a249
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToDeclarationCompletionCommand.kt
@@ -0,0 +1,38 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+import com.intellij.idea.ActionsBundle
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus.Experimental
+
+/**
+ * Represents an abstract completion command specifically designed for navigating to declarations
+ * in the code editor.
+ */
+@Experimental
+abstract class AbstractGoToDeclarationCompletionCommand : AbstractActionCompletionCommand("GotoDeclarationOnly",
+ "Go to Declaration",
+ ActionsBundle.message("action.GotoDeclarationOnly.text"),
+ null) {
+ final override fun supportsReadOnly(): Boolean = true
+
+ final override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ return super.isApplicable(offset, psiFile, editor) && hasToShow(offset, psiFile)
+ }
+
+ private fun hasToShow(offset: Int, psiFile: PsiFile): Boolean {
+ val context = (getContext(offset, psiFile)) ?: return false
+ return canNavigateToDeclaration(context)
+ }
+
+ /**
+ * Determines whether it is possible to navigate to a declaration for a given context element in the code.
+ *
+ * @param context the PsiElement representing the context in which the navigation is being evaluated
+ * @return true if navigation to the declaration is possible, false otherwise
+ */
+ abstract fun canNavigateToDeclaration(context: PsiElement): Boolean
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToImplementationCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToImplementationCompletionCommand.kt
new file mode 100644
index 000000000000..23674f7d92aa
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractGoToImplementationCompletionCommand.kt
@@ -0,0 +1,36 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+import com.intellij.idea.ActionsBundle
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+
+/**
+ * Represents an abstract command to navigate to the implementation(s)
+ * of a given element within a code editor during code completion processes.
+ */
+@ApiStatus.Experimental
+abstract class AbstractGoToImplementationCompletionCommand : AbstractActionCompletionCommand("GotoImplementation",
+ "Go to Implementation",
+ ActionsBundle.message("action.GotoImplementation.text"),
+ null) {
+ final override fun supportsReadOnly(): Boolean = true
+
+ final override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ if (!super.isApplicable(offset, psiFile, editor)) return false
+ val element = getContext(offset, psiFile) ?: return false
+ return canGoToImplementation(element, offset)
+ }
+
+ /**
+ * Determines if navigation to the implementation of the specified element is possible.
+ *
+ * @param element the PSI element for which the implementation is to be checked; can be null
+ * @param offset the offset within the element's document, typically representing the caret's position
+ * @return true if navigation to the implementation is possible, otherwise false
+ */
+ abstract fun canGoToImplementation(element: PsiElement, offset: Int): Boolean
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractShowUsagesActionCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractShowUsagesActionCompletionCommand.kt
new file mode 100644
index 000000000000..f7a1eb219621
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/AbstractShowUsagesActionCompletionCommand.kt
@@ -0,0 +1,38 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+import com.intellij.find.actions.ShowUsagesAction
+import com.intellij.idea.ActionsBundle
+import com.intellij.lang.injection.InjectedLanguageManager
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus.Experimental
+
+/**
+ * Abstract base class for defining commands that are intended to execute the "Show Usages" action
+ * specifically within the context of code completion.
+ */
+@Experimental
+abstract class AbstractShowUsagesActionCompletionCommand : AbstractActionCompletionCommand(ShowUsagesAction.ID,
+ "Show usages",
+ ActionsBundle.message("action.ShowUsages.text"),
+ null) {
+ final override fun supportsReadOnly(): Boolean = true
+
+ final override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
+ val element = getContext(offset, psiFile) ?: return false
+ return super.isApplicable(offset, psiFile, editor) && hasToShow(element) &&
+ !InjectedLanguageManager.getInstance(psiFile.project).isInjectedFragment(psiFile)
+ }
+
+ /**
+ * Determines whether a given PSI element should be used to show its usages
+ * in the context of the command execution.
+ *
+ * @param element the PSI element being checked; may be null
+ * @return true if the element should be shown, false otherwise
+ */
+ abstract fun hasToShow(element: PsiElement): Boolean
+}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectErrorFixCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectErrorFixCompletionCommand.kt
similarity index 92%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectErrorFixCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectErrorFixCompletionCommand.kt
index bfd78960ec17..87613d733ffe 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectErrorFixCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectErrorFixCompletionCommand.kt
@@ -1,9 +1,9 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+package com.intellij.codeInsight.completion.command.commands
import com.intellij.analysis.AnalysisBundle.message
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.codeInsight.completion.commands.core.HighlightInfoLookup
+import com.intellij.codeInsight.completion.command.CompletionCommand
+import com.intellij.codeInsight.completion.command.HighlightInfoLookup
import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator
import com.intellij.codeInsight.daemon.impl.HighlightInfo.IntentionActionDescriptor
import com.intellij.codeInsight.daemon.impl.HighlightVisitorBasedInspection.runAnnotatorsInGeneralHighlighting
@@ -18,9 +18,11 @@ import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil
import kotlinx.coroutines.job
+import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Icon
+@ApiStatus.Experimental
internal class DirectErrorFixCompletionCommand(
override val name: @Nls String,
override val priority: Int?,
@@ -58,7 +60,6 @@ internal class DirectErrorFixCompletionCommand(
for (fix in fixes) {
if (fix.action.text == name) {
return@jobToIndicator fix.action
- break
}
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectInspectionFixCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectInspectionFixCompletionCommand.kt
similarity index 91%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectInspectionFixCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectInspectionFixCompletionCommand.kt
index 219349ae735a..1c0fde8db3d3 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectInspectionFixCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectInspectionFixCompletionCommand.kt
@@ -1,9 +1,9 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
import com.intellij.analysis.AnalysisBundle.message
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.codeInsight.completion.commands.core.HighlightInfoLookup
+import com.intellij.codeInsight.completion.command.CompletionCommand
+import com.intellij.codeInsight.completion.command.HighlightInfoLookup
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler.availableFor
@@ -25,10 +25,12 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil
import com.intellij.psi.util.PsiTreeUtil
import kotlinx.coroutines.job
+import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Icon
-class DirectInspectionFixCompletionCommand(
+@ApiStatus.Experimental
+internal class DirectInspectionFixCompletionCommand(
private val inspectionId: String,
override val name: @Nls String,
override val priority: Int?,
@@ -47,7 +49,7 @@ class DirectInspectionFixCompletionCommand(
val topLevelOffset = injectedLanguageManager.injectedToHost(psiFile, offset)
val isInjected = topLevelFile != psiFile
- var action: IntentionAction? = runWithModalProgressBlocking(psiFile.project, message("scanning.scope.progress.title")) {
+ val action: IntentionAction? = runWithModalProgressBlocking(psiFile.project, message("scanning.scope.progress.title")) {
val profileToUse = ProjectInspectionProfileManager.Companion.getInstance(psiFile.project).getCurrentProfile()
val inspectionWrapper = InspectionProfileWrapper(profileToUse)
var inspectionTool = inspectionWrapper.inspectionProfile.getInspectionTool(inspectionId, psiFile.project)
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectIntentionCommandProvider.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectIntentionCommandProvider.kt
similarity index 87%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectIntentionCommandProvider.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectIntentionCommandProvider.kt
index 9a6af98fd339..1575a2760278 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/DirectIntentionCommandProvider.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/DirectIntentionCommandProvider.kt
@@ -1,20 +1,12 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.codeInsight.completion.commands.api.CommandCompletionProviderContext
-import com.intellij.codeInsight.completion.commands.api.CommandProvider
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.codeInsight.completion.commands.core.CommandCompletionUnsupportedOperationException
-import com.intellij.codeInsight.completion.commands.core.HighlightInfoLookup
+import com.intellij.codeInsight.completion.command.*
import com.intellij.codeInsight.daemon.HighlightDisplayKey
import com.intellij.codeInsight.daemon.impl.*
import com.intellij.codeInsight.daemon.impl.HighlightInfo.IntentionActionDescriptor
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass.IntentionsInfo
-import com.intellij.codeInsight.daemon.impl.quickfix.CreateGetterOrSetterFix
-import com.intellij.codeInsight.daemon.impl.quickfix.ExpensivePsiIntentionAction
-import com.intellij.codeInsight.intention.EmptyIntentionAction
-import com.intellij.codeInsight.intention.IntentionAction
-import com.intellij.codeInsight.intention.IntentionManager
+import com.intellij.codeInsight.intention.*
import com.intellij.codeInsight.intention.impl.CachedIntentions
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewUnsupportedOperationException
@@ -28,10 +20,10 @@ import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
import com.intellij.codeInspection.ex.QuickFixWrapper
import com.intellij.icons.AllIcons
import com.intellij.lang.Language
+import com.intellij.lang.LanguageExtension
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.lang.annotation.HighlightSeverity.INFORMATION
import com.intellij.lang.injection.InjectedLanguageManager
-import com.intellij.modcommand.ModCommandService
import com.intellij.openapi.application.readAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
@@ -43,8 +35,11 @@ import com.intellij.openapi.progress.runBlockingCancellable
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.openapi.project.ProjectTypeService
+import com.intellij.openapi.util.Iconable
+import com.intellij.openapi.util.Iconable.ICON_FLAG_VISIBILITY
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
+import com.intellij.openapi.util.registry.Registry
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager.Companion.getInstance
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil
@@ -53,10 +48,17 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.job
+import org.jetbrains.annotations.ApiStatus
import java.util.function.Predicate
+/**
+ * Provides supplying completion commands
+ * based on intentions, errors, and inspections within the given context.
+ */
+@ApiStatus.Experimental
class DirectIntentionCommandProvider : CommandProvider {
override fun getCommands(context: CommandCompletionProviderContext): List {
+ if (!Registry.`is`("ide.completion.command.enabled")) return emptyList()
return runBlockingCancellable {
val originalEditor = context.originalEditor
val psiFile = context.psiFile
@@ -79,7 +81,7 @@ class DirectIntentionCommandProvider : CommandProvider {
}
val asyncInspections = if (cachedInspectionCommand == null) asyncInspectionHighlighting(psiFile, editor, offset) else null
- val asyncIntentions = asyncIntentions(editor, psiFile, originalPsiFile)
+ val asyncIntentions = asyncIntentions(editor, psiFile, originalPsiFile, offset)
val errors = asyncErrorHighlighting?.await()
errors?.let {
@@ -128,7 +130,7 @@ class DirectIntentionCommandProvider : CommandProvider {
offset: Int,
): Deferred> = async {
return@async readAction {
-
+ val intentionCommandSkipper = IntentionCommandSkipper.EP_NAME.forLanguage(psiFile.language)
val injectedLanguageManager = InjectedLanguageManager.getInstance(psiFile.project)
val topLevelFile = injectedLanguageManager.getTopLevelFile(psiFile)
val topLevelEditor = InjectedLanguageEditorUtil.getTopLevelEditor(editor)
@@ -175,13 +177,8 @@ class DirectIntentionCommandProvider : CommandProvider {
val level = ProblemDescriptorUtil.highlightTypeFromDescriptor(descriptor, severity, severityRegistrar)
for (i in 0..fixes.size - 1) {
val action = QuickFixWrapper.wrap(descriptor, i)
- if (action is EmptyIntentionAction || action is ExpensivePsiIntentionAction) continue
- val fix = QuickFixWrapper.unwrap(action)
- if (fix != null) {
- val unwrappedAction = ModCommandService.getInstance().unwrap(fix)
- //skip, probably create extensions
- if (unwrappedAction is CreateGetterOrSetterFix) continue
- }
+ if (action is EmptyIntentionAction) continue
+ if (intentionCommandSkipper != null && intentionCommandSkipper.skip(action, psiFile, offset)) continue
if (!isInjected && !ShowIntentionActionsHandler.availableFor(topLevelFile, topLevelEditor, topLevelOffset, action)) continue
if (isInjected && !ShowIntentionActionsHandler.availableFor(psiFile, editor, offset, action)) continue
val priority = if (level.getSeverity(null) == INFORMATION) 70 else 80
@@ -245,14 +242,19 @@ class DirectIntentionCommandProvider : CommandProvider {
editor: Editor,
psiFile: PsiFile,
originalFile: PsiFile,
+ offset: Int,
): Deferred> = async {
return@async readAction {
-
+ val intentionCommandSkipper = IntentionCommandSkipper.EP_NAME.forLanguage(psiFile.language)
val availableIntentions = IntentionManager.getInstance().getAvailableIntentions(mutableListOf(originalFile.language.id))
val actionsToShow = IntentionsInfo()
for (action in availableIntentions) {
+ val intentionAction = IntentionActionDelegate.unwrap(action)
val descriptor =
- IntentionActionDescriptor(action, null, null, null, null, null, null, null)
+ IntentionActionDescriptor(action, null, null,
+ if (intentionAction is Iconable)
+ intentionAction.getIcon(ICON_FLAG_VISIBILITY)
+ else null, null, null, null, null)
actionsToShow.intentionsToShow.add(descriptor)
}
val dumbService = DumbService.getInstance(originalFile.project)
@@ -267,6 +269,7 @@ class DirectIntentionCommandProvider : CommandProvider {
ProgressManager.checkCanceled()
if (!dumbService.isUsableInCurrentContext(intention) ||
!intention.action.isAvailable(originalFile.project, editor, psiFile) &&
+ //todo temporary workaround for AI
intention.action.familyName !in ("AI Actions…") ||
!filter.test(intention.action)) {
toRemove.add(intention)
@@ -286,18 +289,15 @@ class DirectIntentionCommandProvider : CommandProvider {
intentionsCache.wrapAndUpdateActions(actionsToShow, false)
val result = mutableListOf()
for (intention in intentionsCache.intentions) {
- if (intention.action is EmptyIntentionAction || intention.action is ExpensivePsiIntentionAction) continue
+ if (intention.action is EmptyIntentionAction ||
+ intentionCommandSkipper != null && intentionCommandSkipper.skip(intention.action, psiFile, offset)) continue
val intentionCommand =
- IntentionCompletionCommand(intention, 50, AllIcons.Actions.IntentionBulbGrey, null)
+ IntentionCompletionCommand(intention, 50, intention.icon ?: AllIcons.Actions.IntentionBulbGrey, null)
result.add(intentionCommand)
}
return@readAction result
}
}
-
- override fun getId(): String {
- return "DirectIntentionCommandProvider"
- }
}
internal fun getLineRange(psiFile: PsiFile, offset: Int): TextRange {
@@ -343,3 +343,13 @@ private fun getInspectionTools(profile: InspectionProfileWrapper, file: PsiFile)
}
return enabled
}
+
+@ApiStatus.Experimental
+interface IntentionCommandSkipper {
+ companion object {
+ internal val EP_NAME: LanguageExtension = LanguageExtension("com.intellij.codeInsight.completion.intention.skipper")
+ }
+
+ fun skip(action: CommonIntentionAction, psiFile: PsiFile, offset: Int): Boolean = false
+}
+
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ExtensionBasedCommandProvider.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ExtensionBasedCommandProvider.kt
new file mode 100644
index 000000000000..b4a65d498224
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ExtensionBasedCommandProvider.kt
@@ -0,0 +1,35 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+
+import com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
+import com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
+import com.intellij.codeInsight.completion.command.CommandProvider
+import com.intellij.codeInsight.completion.command.CompletionCommand
+import com.intellij.lang.LanguageExtension
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.util.registry.Registry
+import org.jetbrains.annotations.ApiStatus
+
+/**
+ * An implementation of the CommandProvider interface that supplies completion commands
+ * registered through extension points ('com.intellij.codeInsight.completion.applicable.command') for specific programming languages.
+ */
+@ApiStatus.Experimental
+internal class ExtensionPointCommandProvider : CommandProvider, DumbAware {
+ override fun getCommands(context: CommandCompletionProviderContext): List {
+ if (!Registry.`is`("ide.completion.command.enabled")) return emptyList()
+ val completionCommands =
+ DumbService.getInstance(context.project)
+ .filterByDumbAwareness(EP_NAME.allForLanguage(context.psiFile.language))
+ return completionCommands.filter {
+ !(context.isReadOnly && !it.supportsReadOnly()) && it.isApplicable(context.offset, context.psiFile, context.editor)
+ }
+ }
+
+ override fun supportsReadOnly(): Boolean {
+ return true
+ }
+}
+
+private val EP_NAME: LanguageExtension = LanguageExtension("com.intellij.codeInsight.completion.applicable.command")
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntentionCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/IntentionCompletionCommand.kt
similarity index 72%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntentionCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/IntentionCompletionCommand.kt
index fc03982020f8..e2c077c6cc5c 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/IntentionCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/IntentionCompletionCommand.kt
@@ -1,16 +1,18 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.codeInsight.completion.commands.api.CompletionCommand
-import com.intellij.codeInsight.completion.commands.core.HighlightInfoLookup
+import com.intellij.codeInsight.completion.command.CompletionCommand
+import com.intellij.codeInsight.completion.command.HighlightInfoLookup
import com.intellij.codeInsight.intention.impl.IntentionActionWithTextCaching
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Icon
-class IntentionCompletionCommand(
+@ApiStatus.Experimental
+internal class IntentionCompletionCommand(
private val intentionAction: IntentionActionWithTextCaching,
override val priority: Int?,
override val icon: Icon?,
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/LineCommentCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/LineCommentCompletionCommand.kt
similarity index 75%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/LineCommentCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/LineCommentCompletionCommand.kt
index 5ac4a3134668..6c448bfee005 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/LineCommentCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/LineCommentCompletionCommand.kt
@@ -1,10 +1,17 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
import com.intellij.idea.ActionsBundle
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus.Experimental
+/**
+ * A command that executes the "Comment by Line Comment" action
+ * within the context of code completion.
+ */
+@Experimental
class LineCommentCompletionCommand : AbstractActionCompletionCommand("CommentByLineComment",
"Comment line",
ActionsBundle.actionText("CommentByLineComment"),
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/OptimizeImportCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/OptimizeImportCompletionCommand.kt
similarity index 72%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/OptimizeImportCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/OptimizeImportCompletionCommand.kt
index 764a7fbd6dd3..4dcc3a910136 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/OptimizeImportCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/OptimizeImportCompletionCommand.kt
@@ -1,11 +1,17 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
import com.intellij.idea.ActionsBundle
import com.intellij.lang.injection.InjectedLanguageManager
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus.Experimental
+/**
+ * A command that triggers the "Optimize Imports" action within the context of code completion.
+ */
+@Experimental
class OptimizeImportCompletionCommand : AbstractActionCompletionCommand("OptimizeImports",
"Optimize imports",
ActionsBundle.message("action.OptimizeImports.text"),
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ProjectViewCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ProjectViewCompletionCommand.kt
similarity index 64%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ProjectViewCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ProjectViewCompletionCommand.kt
index f625d71ff919..206a9f9f4c5c 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/ProjectViewCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/ProjectViewCompletionCommand.kt
@@ -1,14 +1,20 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
+import com.intellij.codeInsight.CodeInsightBundle
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
import com.intellij.ide.actions.ActivateToolWindowAction.Manager
-import com.intellij.java.JavaBundle
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+/**
+ * A completion command, which triggers the "Project" tool window in the IDE.
+ */
+@ApiStatus.Experimental
class ProjectViewCompletionCommand : AbstractActionCompletionCommand(Manager.getActionIdForToolWindow("Project"),
"Project tool",
- JavaBundle.message("command.completion.project.tool.text"),
+ CodeInsightBundle.message("command.completion.project.tool.text"),
null,
-150) {
override fun supportsReadOnly(): Boolean = true
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaPsiElementCommentCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/PsiElementCommentCompletionCommand.kt
similarity index 79%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaPsiElementCommentCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/PsiElementCommentCompletionCommand.kt
index 2897459293c4..199bd230a3c3 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaPsiElementCommentCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/PsiElementCommentCompletionCommand.kt
@@ -1,15 +1,16 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.java.JavaBundle
+import com.intellij.codeInsight.CodeInsightBundle
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
-class JavaPsiElementCommentCompletionCommand : AbstractActionCompletionCommand("CommentByLineComment",
- "Comment element",
- JavaBundle.message("java.psi.element.comment.completion.command.text"),
- null) {
+class PsiElementCommentCompletionCommand : AbstractActionCompletionCommand("CommentByLineComment",
+ "Comment element",
+ 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
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RecentFilesCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RecentFilesCompletionCommand.kt
similarity index 61%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RecentFilesCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RecentFilesCompletionCommand.kt
index 247306ef231a..20bbea120110 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RecentFilesCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RecentFilesCompletionCommand.kt
@@ -1,13 +1,19 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.java.JavaBundle
+import com.intellij.codeInsight.CodeInsightBundle
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
+import org.jetbrains.annotations.ApiStatus
+/**
+ * This command enables triggering the "Recent Files" action during code completion.
+ */
+@ApiStatus.Experimental
class RecentFilesCompletionCommand : AbstractActionCompletionCommand("RecentFiles",
"Recent files",
- JavaBundle.message("command.completion.recent.files.text"),
+ CodeInsightBundle.message("command.completion.recent.files.text"),
null,
-150) {
override fun supportsReadOnly(): Boolean = true
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RenameActionCompletionCommand.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RenameActionCompletionCommand.kt
similarity index 77%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RenameActionCompletionCommand.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RenameActionCompletionCommand.kt
index 45ff01ad0fbe..346ff55634b8 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/RenameActionCompletionCommand.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/RenameActionCompletionCommand.kt
@@ -1,16 +1,19 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.codeInsight.completion.commands.api.getTargetContext
+import com.intellij.codeInsight.completion.command.AbstractActionCompletionCommand
+import com.intellij.codeInsight.completion.command.getTargetContext
import com.intellij.idea.ActionsBundle
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiNamedElement
+import org.jetbrains.annotations.ApiStatus
+@ApiStatus.Experimental
class RenameActionCompletionCommand : AbstractActionCompletionCommand(IdeActions.ACTION_RENAME,
- "rename",
+ "Rename",
ActionsBundle.message("action.RenameElement.text"),
null) {
override fun isApplicable(offset: Int, psiFile: PsiFile, editor: Editor?): Boolean {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/SimpleRunMarkerCommandProvider.kt b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/SimpleRunMarkerCommandProvider.kt
similarity index 91%
rename from java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/SimpleRunMarkerCommandProvider.kt
rename to platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/SimpleRunMarkerCommandProvider.kt
index ec232e1126d2..42ae4bb9b8c1 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/SimpleRunMarkerCommandProvider.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/command/commands/SimpleRunMarkerCommandProvider.kt
@@ -1,7 +1,8 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.completion.commands.impl
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.command.commands
-import com.intellij.codeInsight.completion.commands.api.*
+import com.intellij.analysis.AnalysisBundle
+import com.intellij.codeInsight.completion.command.*
import com.intellij.codeInsight.daemon.MergeableLineMarkerInfo
import com.intellij.codeInsight.daemon.impl.GutterIntentionAction
import com.intellij.codeInsight.daemon.impl.IntentionActionFilter
@@ -23,13 +24,19 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.text.StringUtil
+import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.util.containers.JBIterable.from
+import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import java.util.function.Predicate
import javax.swing.Icon
+/**
+ * A provider for run marker-related completion commands in the code editor.
+ */
+@ApiStatus.Experimental
class SimpleRunMarkerCommandProvider : CommandProvider {
override fun getCommands(context: CommandCompletionProviderContext): List {
return runBlockingCancellable {
@@ -88,10 +95,6 @@ class SimpleRunMarkerCommandProvider : CommandProvider {
return@runBlockingCancellable commands
}
}
-
- override fun getId(): String {
- return "RunMarkerCommandProvider"
- }
}
private fun collectActions(
@@ -137,7 +140,9 @@ private class RunMarkerCompletionCommand(
get() = ""
override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
- val (_, collectedActions) = collectActions(psiFile, offsetElement, psiFile.project)
+ val (_, collectedActions) = runWithModalProgressBlocking(psiFile.project, AnalysisBundle.message("scanning.scope.progress.title")) {
+ collectActions(psiFile, offsetElement, psiFile.project)
+ }
val cachedIntentions = CachedIntentions(psiFile.project, psiFile, editor)
val intentionsInfo = ShowIntentionsPass.IntentionsInfo()
intentionsInfo.guttersToShow.addAll(collectedActions)
diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
index e2cc96a9e55d..3a534fef47e1 100644
--- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
@@ -748,5 +748,22 @@
qualifiedName="com.intellij.microservices.featuresAvailabilityProvider" dynamic="true"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml
index e5f806672bc1..5118c154a25e 100644
--- a/platform/platform-resources/src/META-INF/LangExtensions.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensions.xml
@@ -726,7 +726,8 @@
id="liveTemplates" order="first"/>
-
+
@@ -736,6 +737,13 @@
+
+
+
+
+
+
+
@@ -1684,6 +1692,11 @@
+
+
+
@@ -1862,5 +1875,7 @@
topic="com.intellij.platform.backend.workspace.WorkspaceModelChangeListener"/>
+
-
+
\ No newline at end of file