mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[command-completion] IDEA-359174 first draft of command completion
- move to platform part GitOrigin-RevId: 9dde441fccb6ea470faa08a8df8bad75f60fcad4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
59bea5195f
commit
6150820425
@@ -292,20 +292,6 @@
|
||||
|
||||
<extensionPoint qualifiedName="com.intellij.gotoByName.defaultProvider.ignoreLanguage" dynamic="true"
|
||||
beanClass="com.intellij.ide.util.gotoByName.IgnoreLanguageInDefaultProvider"/>
|
||||
|
||||
|
||||
<!--todo move to main-->
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.command.factory"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.completion.commands.CommandCompletionFactory"/>
|
||||
</extensionPoint>
|
||||
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.command"
|
||||
dynamic="true"
|
||||
interface="com.intellij.codeInsight.completion.commands.api.CompletionCommand" />
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.command.provider"
|
||||
dynamic="true"
|
||||
interface="com.intellij.codeInsight.completion.commands.api.CommandProvider" />
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
@@ -1503,29 +1489,29 @@
|
||||
implementationClass="com.intellij.codeInsight.completion.JvmLoggerCompletionContributor"/>
|
||||
<completion.contributor language="JAVA" id="jigsaw"
|
||||
implementationClass="com.intellij.codeInsight.completion.JigsawCompletionContributor"/>
|
||||
<nonWriteAccessTypedHandler implementation="com.intellij.codeInsight.completion.commands.core.CommandCompletionNonWriteAccessTypedHandler" id="commandCompletion"/>
|
||||
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.InlineVariableCompletionCommand" />
|
||||
<codeInsight.completion.command.provider implementation="com.intellij.codeInsight.completion.commands.impl.ExtensionPointCommandProvider" />
|
||||
<codeInsight.completion.command.provider implementation="com.intellij.codeInsight.completion.commands.impl.DirectIntentionCommandProvider" order="last"/>
|
||||
<codeInsight.completion.command.provider implementation="com.intellij.codeInsight.completion.commands.impl.GenerateCommandProvider" />
|
||||
<codeInsight.completion.command.provider implementation="com.intellij.codeInsight.completion.commands.impl.SimpleRunMarkerCommandProvider" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.GoToDeclarationCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.RenameActionCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.OptimizeImportCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.FormatCodeCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.RecentFilesCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.ProjectViewCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.LineCommentCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.JavaPsiElementCommentCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.IntroduceVariableCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.ShowUsagesActionCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.GenerateGetterSetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.GenerateSetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.GenerateGetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.DeleteCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.CopyFQNCompletionCommand" />
|
||||
<codeInsight.completion.command implementation="com.intellij.codeInsight.completion.commands.impl.GoToImplementationCompletionCommand" />
|
||||
<codeInsight.completion.command.factory language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.JavaCommandCompletionFactory" />
|
||||
<codeInsight.completion.intention.skipper language="JAVA"
|
||||
implementationClass="com.intellij.codeInsight.completion.commands.JavaCommandCompletionFactory$JavaIntentionCommandSkipper"/>
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.SimpleRunMarkerCommandProvider" />
|
||||
<codeInsight.completion.command.provider language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaGenerateCommandCompletion" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaInlineVariableCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaGoToDeclarationCommandCompletion" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.RenameActionCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.OptimizeImportCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaFormatCodeCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.RecentFilesCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.ProjectViewCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.LineCommentCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.command.commands.PsiElementCommentCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaIntroduceVariableCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaShowUsagesActionCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.GenerateGetterSetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.GenerateSetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.GenerateGetterHandleCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaDeleteCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaCopyFQNCompletionCommand" />
|
||||
<codeInsight.completion.applicable.command language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaGoToImplementationCommandCompletion" />
|
||||
|
||||
<weigher implementationClass="com.intellij.codeInsight.completion.LoggerWeigher" key="completion" id="logger"/>
|
||||
|
||||
@@ -2790,17 +2776,6 @@
|
||||
|
||||
<trigramIndexFilterExcludeExtension implementation="com.intellij.java.impl.find.ngrams.JavaTrigramFilterExcludeExtension"/>
|
||||
|
||||
<codeInsight.completion.command.factory language="JAVA" implementationClass="com.intellij.codeInsight.completion.commands.impl.JavaCommandCompletionFactory" />
|
||||
<completion.contributor language="JAVA" id="commands" order="first, after liveTemplates"
|
||||
implementationClass="com.intellij.codeInsight.completion.commands.core.CommandCompletionContributor"/>
|
||||
<completion.contributor language="TEXT" id="commandsPlain" order="first, after liveTemplates"
|
||||
implementationClass="com.intellij.codeInsight.completion.commands.core.CommandCompletionContributor"/>
|
||||
<lookup.charFilter implementation="com.intellij.codeInsight.completion.commands.core.CommandCompletionCharFilter" order="first" id="commandCompletion"/>
|
||||
<lookup.customizer implementation="com.intellij.codeInsight.completion.commands.core.CommandCompletionLookupCustomizer" order="last" id="commandCompletionLookupCustomizer"/>
|
||||
|
||||
<registryKey key="java.completion.command.enabled" defaultValue="false"
|
||||
description="Enable experimental support command completion" restartRequired="true"/>
|
||||
|
||||
<registryKey key="java.completion.argument.live.template" defaultValue="false"
|
||||
description="When completing a method call, start a live template with all arguments"/>
|
||||
<registryKey key="java.completion.argument.live.template.completion" defaultValue="false"
|
||||
@@ -2879,7 +2854,5 @@
|
||||
topic="com.intellij.refactoring.listeners.RefactoringEventListener"/>
|
||||
<listener class="com.intellij.openapi.roots.impl.LanguageLevelChangedListener"
|
||||
topic="com.intellij.platform.backend.workspace.WorkspaceModelChangeListener"/>
|
||||
<listener class="com.intellij.codeInsight.completion.commands.core.CommandCompletionListener"
|
||||
topic="com.intellij.codeInsight.lookup.LookupManagerListener"/>
|
||||
</projectListeners>
|
||||
</idea-plugin>
|
||||
|
||||
+46
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-44
@@ -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<CommandProvider>
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
-35
@@ -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>(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
|
||||
)
|
||||
-44
@@ -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
|
||||
}
|
||||
}
|
||||
-27
@@ -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<CompletionCommand> {
|
||||
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
|
||||
}
|
||||
}
|
||||
-38
@@ -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()
|
||||
}
|
||||
}
|
||||
-64
@@ -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<CompletionCommand> {
|
||||
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<BaseGenerateAction> = 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"
|
||||
}
|
||||
}
|
||||
-38
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
-35
@@ -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
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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(
|
||||
|
||||
-29
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
-13
@@ -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)
|
||||
+2
-2
@@ -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
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package 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 }
|
||||
}
|
||||
}
|
||||
+17
@@ -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
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package 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
|
||||
}
|
||||
}
|
||||
+35
@@ -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
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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")
|
||||
+6
-6
@@ -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)
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package 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)
|
||||
|
||||
}
|
||||
}
|
||||
-28
@@ -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)
|
||||
}
|
||||
}
|
||||
+228
-9
@@ -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.<caret>() {
|
||||
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 {
|
||||
.<caret>
|
||||
}
|
||||
""".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<caret>
|
||||
}
|
||||
""".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;
|
||||
.<caret>
|
||||
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.<caret>;
|
||||
}
|
||||
""".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;.<caret>
|
||||
}
|
||||
}""".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.<caret>;
|
||||
}
|
||||
}
|
||||
""".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";
|
||||
}
|
||||
}.<caret>""".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.<caret> = "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.<caret>();
|
||||
|
||||
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 <caret>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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,62 @@
|
||||
*a:com.intellij.codeInsight.completion.command.ApplicableCompletionCommand
|
||||
- com.intellij.codeInsight.completion.command.CompletionCommand
|
||||
- <init>():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
|
||||
- <init>(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
|
||||
- <init>():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
|
||||
- <init>(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
|
||||
|
||||
+69
@@ -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<CommandProvider> {
|
||||
if (!Registry.`is`("ide.completion.command.enabled")) return mutableListOf<CommandProvider>()
|
||||
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<CommandProvider>("com.intellij.codeInsight.completion.command.provider")
|
||||
+2
-6
@@ -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<CommandProvider>("com.intellij.codeInsight.completion.command.provider")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,7 +27,7 @@ interface CommandProvider {
|
||||
*/
|
||||
fun getCommands(context: CommandCompletionProviderContext): List<CompletionCommand>
|
||||
|
||||
fun getId(): String
|
||||
fun getId(): String = javaClass.name
|
||||
|
||||
/**
|
||||
* Indicates whether the implementation supports non-written files.
|
||||
+10
-58
@@ -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<ApplicableCompletionCommand>("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
|
||||
}
|
||||
}
|
||||
@ApiStatus.Experimental
|
||||
data class HighlightInfoLookup(
|
||||
val range: TextRange,
|
||||
val attributesKey: TextAttributesKey,
|
||||
val priority: Int, //higher is on the top
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
- <init>(java.lang.String,java.lang.String,java.lang.String,javax.swing.Icon,java.lang.Integer):V
|
||||
- b:<init>(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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
|
||||
@@ -2133,6 +2133,11 @@ f:com.intellij.codeInsight.completion.addingPolicy.PassDirectlyPolicy
|
||||
- <init>():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
|
||||
- <init>():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
|
||||
- <init>(com.intellij.codeInsight.completion.PrefixMatcher,I):V
|
||||
|
||||
+29
-16
@@ -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
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -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<AppCommandC
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.Internal
|
||||
class AppCommandCompletionSettings(
|
||||
var showCounts: Int = 0,
|
||||
)
|
||||
+2
-2
@@ -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.CompletionContributor
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
// 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.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.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.project.IndexNotReadyException
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.ApiStatus.Experimental
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import javax.swing.Icon
|
||||
|
||||
/**
|
||||
* Represents a specialized lookup element intended for usage in command completion scenarios.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@ApiStatus.Experimental
|
||||
internal class CommandCompletionLookupElement(
|
||||
lookupElement: LookupElement,
|
||||
val hostStartOffset: Int,
|
||||
val suffix: String,
|
||||
val icon: Icon?,
|
||||
val highlighting: HighlightInfoLookup?,
|
||||
) : LookupElementDecorator<LookupElement>(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
|
||||
}
|
||||
}
|
||||
+14
-7
@@ -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<Pair<Editor, Int>>("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
|
||||
+92
-29
@@ -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<CompletionParameters?>() {
|
||||
|
||||
@@ -48,7 +54,7 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
context: ProcessingContext,
|
||||
resultSet: CompletionResultSet,
|
||||
) {
|
||||
if (!Registry.`is`("java.completion.command.enabled")) return
|
||||
if (!Registry.`is`("ide.completion.command.enabled")) return
|
||||
resultSet.runRemainingContributors(parameters) {
|
||||
resultSet.passResult(it)
|
||||
}
|
||||
@@ -84,13 +90,14 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
if (!dumbService.isUsableInCurrentContext(commandCompletionFactory)) return
|
||||
|
||||
if (editor.document.textLength != offset &&
|
||||
StringUtil.isJavaIdentifierPart(editor.document.immutableCharSequence[offset])) {
|
||||
StringUtil.isJavaIdentifierPart(editor.document.immutableCharSequence[offset])
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val commandCompletionType = findCommandCompletionType(commandCompletionFactory, isReadOnly, offset, parameters.editor) ?: return
|
||||
val adjustedParameters = try {
|
||||
adjustParameters(commandCompletionType, editor, originalFile, offset, isReadOnly) ?: return
|
||||
adjustParameters(commandCompletionFactory, commandCompletionType, editor, originalFile, offset, isReadOnly) ?: return
|
||||
}
|
||||
catch (_: Exception) {
|
||||
return
|
||||
@@ -101,17 +108,19 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
val copyEditor = MyEditor(adjustedParameters.copyFile, editor.settings)
|
||||
copyEditor.caretModel.moveToOffset(adjustedParameters.offset)
|
||||
|
||||
val withPrefixMatcher = resultSet.withPrefixMatcher(CamelHumpMatcher(resultSet.prefixMatcher.prefix, false, true))
|
||||
val prefix = commandCompletionType.pattern
|
||||
val withPrefixMatcher = resultSet.withPrefixMatcher(CamelHumpMatcher(prefix, false, true))
|
||||
.withRelevanceSorter(createSorter(parameters))
|
||||
|
||||
|
||||
withPrefixMatcher.restartCompletionOnPrefixChange(StandardPatterns.string().with(object : PatternCondition<String>("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<String>("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<CompletionParamete
|
||||
val indexOf = findActualIndex(suffix, text, offset)
|
||||
if (offset - indexOf < 0) return null
|
||||
if (indexOf == 1) {
|
||||
return InvocationCommandType.PartialSuffix(text.substring(offset - indexOf + 1, offset), text.substring(offset - indexOf, offset - indexOf + 1))
|
||||
//one point
|
||||
return InvocationCommandType.PartialSuffix(text.substring(offset - indexOf + 1, offset),
|
||||
text.substring(offset - indexOf, offset - indexOf + 1))
|
||||
}
|
||||
//two points
|
||||
else if (offset - indexOf + 2 <= text.length && text.substring(offset - indexOf, offset - indexOf + 2) == suffix) {
|
||||
return InvocationCommandType.FullSuffix(text.substring(offset - indexOf + 2, offset), text.substring(offset - indexOf, offset - indexOf + 2))
|
||||
return InvocationCommandType.FullSuffix(text.substring(offset - indexOf + 2, offset),
|
||||
text.substring(offset - indexOf, offset - indexOf + 2))
|
||||
}
|
||||
if (indexOf > 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<CompletionParamete
|
||||
) {
|
||||
val element = copyFile.findElementAt(offset - 1)
|
||||
if (element == null) return
|
||||
for (provider in commandCompletionFactory.commandProviders(project)) {
|
||||
for (provider in commandCompletionFactory.commandProviders(project, element.language)) {
|
||||
try {
|
||||
if(isReadOnly && !provider.supportsReadOnly()) continue
|
||||
val commands = provider.getCommands(CommandCompletionProviderContext(project, copyEditor, offset, copyFile, originalEditor, originalOffset, originalFile, isReadOnly))
|
||||
if (isReadOnly && !provider.supportsReadOnly()) continue
|
||||
val commands = provider.getCommands(
|
||||
CommandCompletionProviderContext(project, copyEditor, offset, copyFile, originalEditor, originalOffset, originalFile, isReadOnly))
|
||||
processor.process(commands)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -224,6 +245,7 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
private data class AdjustedCompletionParameters(val copyFile: PsiFile, val offset: Int, val hostAdjustedOffset: Int)
|
||||
|
||||
private fun adjustParameters(
|
||||
commandCompletionFactory: CommandCompletionFactory,
|
||||
commandCompletionType: InvocationCommandType,
|
||||
editor: Editor,
|
||||
originalFile: PsiFile,
|
||||
@@ -240,14 +262,38 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
var adjustedOffset = hostOffset - commandCompletionType.suffix.length - commandCompletionType.pattern.length
|
||||
if (adjustedOffset <= 0) return null
|
||||
val hostAdjustedOffset = adjustedOffset
|
||||
val adjustedText = originalDocument.getText(TextRange(0, adjustedOffset)) + originalDocument.getText(TextRange(hostOffset, originalDocument.textLength))
|
||||
val adjustedText = originalDocument.getText(TextRange(0, adjustedOffset)) + originalDocument.getText(
|
||||
TextRange(hostOffset, originalDocument.textLength))
|
||||
|
||||
|
||||
var file =
|
||||
if (isNonWritten) {
|
||||
originalFile.copy() as PsiFile
|
||||
}else{
|
||||
PsiFileFactory.getInstance(topEditor.project)
|
||||
.createFileFromText(topFile.getName(), topFile.getLanguage(), adjustedText, true, true, false, topFile.virtualFile)
|
||||
val createdFile = originalFile.copy() as PsiFile
|
||||
if (createdFile is PsiFileImpl) {
|
||||
createdFile.setOriginalFile(topFile)
|
||||
}
|
||||
createdFile
|
||||
}
|
||||
else {
|
||||
if (topFile == originalFile) {
|
||||
var createdFile = commandCompletionFactory.createFile(originalFile, adjustedText)
|
||||
if (createdFile == null) {
|
||||
createdFile = PsiFileFactory.getInstance(topEditor.project)
|
||||
.createFileFromText(topFile.getName(), topFile.getLanguage(), adjustedText, true, true, false, topFile.virtualFile)
|
||||
if (createdFile is PsiFileImpl) {
|
||||
createdFile.setOriginalFile(topFile)
|
||||
}
|
||||
}
|
||||
createdFile
|
||||
}
|
||||
else {
|
||||
val createdFile = PsiFileFactory.getInstance(topEditor.project)
|
||||
.createFileFromText(topFile.getName(), topFile.getLanguage(), adjustedText, true, true, false, topFile.virtualFile)
|
||||
if (createdFile is PsiFileImpl) {
|
||||
createdFile.setOriginalFile(topFile)
|
||||
}
|
||||
createdFile
|
||||
}
|
||||
}
|
||||
|
||||
if (file is PsiFileImpl) {
|
||||
@@ -266,7 +312,8 @@ internal class CommandCompletionProvider : CompletionProvider<CompletionParamete
|
||||
class CommandCompletionUnsupportedOperationException
|
||||
: UnsupportedOperationException("It's unexpected to invoke this method on a command completion calculating.")
|
||||
|
||||
private class MyEditor(psiFileCopy: PsiFile, private val settings: EditorSettings) : ImaginaryEditor(psiFileCopy.project, psiFileCopy.viewProvider.document!!) {
|
||||
private class MyEditor(psiFileCopy: PsiFile, private val settings: EditorSettings) : ImaginaryEditor(psiFileCopy.project,
|
||||
psiFileCopy.viewProvider.document!!) {
|
||||
override fun notImplemented(): RuntimeException = throw CommandCompletionUnsupportedOperationException()
|
||||
|
||||
override fun isViewer(): Boolean = false
|
||||
@@ -296,6 +343,7 @@ internal sealed interface InvocationCommandType {
|
||||
|
||||
data class PartialSuffix(override val pattern: String, override val suffix: String) : InvocationCommandType
|
||||
data class FullSuffix(override val pattern: String, override val suffix: String) : InvocationCommandType
|
||||
data class FullLine(override val pattern: String, override val suffix: String) : InvocationCommandType
|
||||
}
|
||||
|
||||
internal fun findActualIndex(suffix: String, text: CharSequence, offset: Int): Int {
|
||||
@@ -315,7 +363,8 @@ internal fun findActualIndex(suffix: String, text: CharSequence, offset: Int): I
|
||||
val currentSuffix = text[offset - shift]
|
||||
if (currentSuffixFiltered == suffix || currentSuffix == suffix[0]) {
|
||||
if (suffix.length == 2 && suffix.first() == suffix.last() &&
|
||||
text.substring(offset - shift - 1, offset - shift + suffix.length - 1) == suffix) {
|
||||
text.substring(offset - shift - 1, offset - shift + suffix.length - 1) == suffix
|
||||
) {
|
||||
indexOf = shift + 1
|
||||
}
|
||||
else {
|
||||
@@ -328,5 +377,19 @@ internal fun findActualIndex(suffix: String, text: CharSequence, offset: Int): I
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indexOf == 0) {
|
||||
var currentIndex = 1
|
||||
while (offset - currentIndex >= 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
|
||||
}
|
||||
+31
-12
@@ -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<HintRenderer?> = editor.inlayModel.addInlineElement(endOffset, true, EditorLineStripeTextRenderer(" " + JavaBundle.message("command.completion.filter.hint")))
|
||||
val inlineElement: Inlay<HintRenderer?> = 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<RangeHighlighter>()
|
||||
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<CommandCompletionService>()
|
||||
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<CommandCompletionService>()
|
||||
val editor = lookupImpl.editor
|
||||
+9
-4
@@ -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<LookupElement?> {
|
||||
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
|
||||
+39
@@ -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
|
||||
}
|
||||
+47
@@ -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
|
||||
}
|
||||
+97
@@ -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<CompletionCommand> {
|
||||
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<CodeInsightAction> = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -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
|
||||
}
|
||||
+36
@@ -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
|
||||
}
|
||||
+38
@@ -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
|
||||
}
|
||||
+5
-4
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-6
@@ -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)
|
||||
+40
-30
@@ -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<CompletionCommand> {
|
||||
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<List<CompletionCommand>> = 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<List<CompletionCommand>> = 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<CompletionCommand>()
|
||||
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<IntentionCommandSkipper> = LanguageExtension<IntentionCommandSkipper>("com.intellij.codeInsight.completion.intention.skipper")
|
||||
}
|
||||
|
||||
fun skip(action: CommonIntentionAction, psiFile: PsiFile, offset: Int): Boolean = false
|
||||
}
|
||||
|
||||
+35
@@ -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<CompletionCommand> {
|
||||
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<ApplicableCompletionCommand> = LanguageExtension<ApplicableCompletionCommand>("com.intellij.codeInsight.completion.applicable.command")
|
||||
+7
-5
@@ -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?,
|
||||
+9
-2
@@ -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"),
|
||||
+8
-2
@@ -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"),
|
||||
+10
-4
@@ -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
|
||||
+8
-7
@@ -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
|
||||
+10
-4
@@ -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
|
||||
+7
-4
@@ -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 {
|
||||
+13
-8
@@ -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<CompletionCommand> {
|
||||
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)
|
||||
@@ -748,5 +748,22 @@
|
||||
qualifiedName="com.intellij.microservices.featuresAvailabilityProvider" dynamic="true"/>
|
||||
<extensionPoint interface="com.intellij.microservices.oas.serialization.OasSerializationCompatibilityProvider"
|
||||
qualifiedName="com.intellij.microservices.oasSerializationCompatibilityProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.command.factory"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.completion.command.CommandCompletionFactory"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.command.provider"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.completion.command.CommandProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.applicable.command"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.completion.command.ApplicableCompletionCommand"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.completion.intention.skipper"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.completion.command.commands.IntentionCommandSkipper"/>
|
||||
</extensionPoint>
|
||||
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -726,7 +726,8 @@
|
||||
id="liveTemplates" order="first"/>
|
||||
<completion.contributor id="reference" language="any" order="last"
|
||||
implementationClass="com.intellij.codeInsight.completion.ReferenceBasedCompletionContributor"/>
|
||||
|
||||
<completion.contributor language="any" id="commands" order="first, after liveTemplates"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.CommandCompletionContributor"/>
|
||||
<applicationService serviceImplementation="com.intellij.execution.console.ConsoleFoldingSettings"/>
|
||||
<applicationSettings service="com.intellij.execution.console.ConsoleFoldingSettings"/>
|
||||
|
||||
@@ -736,6 +737,13 @@
|
||||
<lookup.charFilter implementation="com.intellij.codeInsight.completion.DefaultCharFilter" order="last" id="default"/>
|
||||
<lookup.charFilter implementation="com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceCharFilter" id="fileRef"
|
||||
order="before completion"/>
|
||||
<lookup.charFilter implementation="com.intellij.codeInsight.completion.command.CommandCompletionCharFilter" order="first" id="commandCompletion"/>
|
||||
<lookup.customizer implementation="com.intellij.codeInsight.completion.command.CommandCompletionLookupCustomizer" order="last" id="commandCompletionLookupCustomizer"/>
|
||||
|
||||
<codeInsight.completion.command.provider language="" implementationClass="com.intellij.codeInsight.completion.command.commands.ExtensionPointCommandProvider" />
|
||||
<codeInsight.completion.command.provider language="" implementationClass="com.intellij.codeInsight.completion.command.commands.DirectIntentionCommandProvider" order="last"/>
|
||||
|
||||
<nonWriteAccessTypedHandler implementation="com.intellij.codeInsight.completion.command.CommandCompletionNonWriteAccessTypedHandler" id="commandCompletion"/>
|
||||
|
||||
<searchEverywhereClassifier implementation="com.intellij.ide.actions.DefaultSearchEverywhereClassifier"/>
|
||||
<gotoFileContributor implementation="com.intellij.ide.util.gotoByName.DefaultFileNavigationContributor"/>
|
||||
@@ -1684,6 +1692,11 @@
|
||||
<registryKey defaultValue="2000"
|
||||
description="Amount in milliseconds to wait for completion contributors till decide whether to insert the single item"
|
||||
key="ide.completion.auto.insert.item.timeout"/>
|
||||
<registryKey key="ide.completion.command.enabled" defaultValue="false"
|
||||
description="Enable experimental support command completion" restartRequired="true"/>
|
||||
<registryKey key="ide.completion.command.full.line.enabled" defaultValue="false"
|
||||
description="Enable experimental support command completion" restartRequired="true"/>
|
||||
|
||||
<indexableEntityProvider implementation="com.intellij.util.indexing.roots.LibraryPropertyEntityIndexableEntityProvider"/>
|
||||
<indexableEntityProvider implementation="com.intellij.util.indexing.roots.CustomSourceRootPropertyIndexableEntityProvider"/>
|
||||
<indexableEntityProvider implementation="com.intellij.util.indexing.roots.ModuleDependencyEntitiesIndexableEntityProvider"/>
|
||||
@@ -1862,5 +1875,7 @@
|
||||
topic="com.intellij.platform.backend.workspace.WorkspaceModelChangeListener"/>
|
||||
<listener class="com.intellij.workspaceModel.ide.impl.legacyBridge.module.ModuleBridgeCleaner"
|
||||
topic="com.intellij.platform.backend.workspace.WorkspaceModelChangeListener"/>
|
||||
<listener class="com.intellij.codeInsight.completion.command.CommandCompletionListener"
|
||||
topic="com.intellij.codeInsight.lookup.LookupManagerListener"/>
|
||||
</projectListeners>
|
||||
</idea-plugin>
|
||||
</idea-plugin>
|
||||
Reference in New Issue
Block a user