IJPL-207762 support command completion completion items on frontend

GitOrigin-RevId: 7efdfb02dad77e0ee9ca276e14b2b6de89f53120
This commit is contained in:
Max Medvedev
2026-02-14 15:01:54 +00:00
committed by intellij-monorepo-bot
parent 7bae32b0ea
commit a535b4d067
5 changed files with 78 additions and 13 deletions
@@ -19,6 +19,8 @@ interface NewRdCompletionSupport {
*/
fun scheduleAutopopup(project: Project, editor: Editor, completionType: CompletionType)
fun isFrontendForIntelliJBackendImpl(): Boolean
companion object {
@JvmStatic
fun isFrontendRdCompletionOn(): Boolean = service<NewRdCompletionSupport>().isFrontendRdCompletionOnImpl()
@@ -32,6 +34,9 @@ interface NewRdCompletionSupport {
@JvmStatic
fun getInstance(): NewRdCompletionSupport = service<NewRdCompletionSupport>()
fun isFrontendForIntelliJBackend(): Boolean =
getInstance().isFrontendForIntelliJBackendImpl()
}
}
@@ -40,4 +45,6 @@ internal class NoOpNewCompletionSupport : NewRdCompletionSupport {
override fun scheduleAutopopup(project: Project, editor: Editor, completionType: CompletionType) =
throw UnsupportedOperationException("Is not expected to be called, use AutopopupController directly instead")
override fun isFrontendForIntelliJBackendImpl(): Boolean = false
}
@@ -3,6 +3,7 @@ package com.intellij.platform.completion.common.protocol
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase
import com.intellij.codeInsight.completion.CompletionResult
import com.intellij.codeInsight.completion.command.RemDevCommandCompletionHelpers
import com.intellij.codeInsight.lookup.AutoCompletionPolicy
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementInsertStopper
@@ -24,6 +25,7 @@ data class RpcCompletionItem(
val shouldStopLookupInsertion: Boolean = false,
val isDirectInsertion: Boolean = false,
val isWorthShowingInAutoPopup: Boolean = false,
val commandState: RemDevCommandCompletionHelpers.CommandState? = null
) {
override fun toString(): String = buildToString("RpcCompletionItem") {
field("id", id)
@@ -61,6 +63,7 @@ fun CompletionResult.toRpc(): RpcCompletionItem {
isDirectInsertion = element.getUserData(CodeCompletionHandlerBase.DIRECT_INSERTION) != null,
prefixMatcher = prefixMatcher.toRpc(id),
isWorthShowingInAutoPopup = element.isWorthShowingInAutoPopup(),
commandState = RemDevCommandCompletionHelpers.getCommandState(element)
)
}
@@ -2,6 +2,8 @@
package com.intellij.codeInsight.completion.command
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.completion.command.RemDevCommandCompletionHelpers.isCommand
import com.intellij.codeInsight.completion.command.RemDevCommandCompletionHelpers.isPostfix
import com.intellij.codeInsight.completion.command.configuration.ApplicationCommandCompletionService
import com.intellij.codeInsight.daemon.impl.HintRenderer
import com.intellij.codeInsight.editorLineStripeHint.EditorLineStripeTextRenderer
@@ -16,7 +18,6 @@ import com.intellij.codeInsight.lookup.LookupManagerListener
import com.intellij.codeInsight.lookup.impl.LookupCustomizer
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.template.impl.TemplateColors
import com.intellij.codeInsight.template.postfix.completion.PostfixTemplateLookupElement
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings
import com.intellij.lang.Language
import com.intellij.lang.LanguageExtension
@@ -136,7 +137,7 @@ internal class CommandCompletionService(
if (showIfMeaningless) {
lookup.showIfMeaningless() // stop hiding
}
lookup.arranger.additionalMatcher = CommandCompletionLookupItemMatcher(PostfixTemplatesSettings.getInstance().isShowAsSeparateGroup)
lookup.arranger.additionalMatcher = CommandCompletionLookupItemMatcher(PostfixTemplatesSettings.getInstance().isShowAsSeparateGroup) // todo settings move frontend
lookup.arranger.prefixChanged(lookup)
lookup.requestResize()
lookup.refreshUi(false, true)
@@ -186,15 +187,14 @@ internal class CommandCompletionService(
}
private class CommandCompletionLookupItemMatcher(private val showPostfixAsSeparateGroup: Boolean) : Condition<LookupElement> {
override fun value(e: LookupElement): Boolean =
e.`as`(CommandCompletionLookupElement::class.java) != null ||
(showPostfixAsSeparateGroup && e.`as`(PostfixTemplateLookupElement::class.java) != null)
override fun value(element: LookupElement): Boolean =
isCommand(element) ||
(showPostfixAsSeparateGroup && isPostfix(element))
}
private object NotPostfixCompletionLookupItemMatcher : Condition<LookupElement> {
override fun value(e: LookupElement?): Boolean {
return e != null && e.`as`(PostfixTemplateLookupElement::class.java) == null
}
override fun value(element: LookupElement): Boolean =
!isPostfix(element)
}
}
@@ -0,0 +1,39 @@
// Copyright 2000-2026 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.lookup.LookupElement
import com.intellij.codeInsight.template.postfix.completion.PostfixTemplateLookupElement
import com.intellij.openapi.util.Key
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
object RemDevCommandCompletionHelpers {
enum class CommandState {
Postfix,
Command,
}
private val COMMAND_FLAG: Key<CommandState> = Key("COMMAND_FLAG")
fun isPostfix(element: LookupElement): Boolean =
element.`as`(PostfixTemplateLookupElement::class.java) != null ||
element.getUserData(COMMAND_FLAG) == CommandState.Postfix
fun isCommand(element: LookupElement): Boolean =
element.`as`(CommandCompletionLookupElement::class.java) != null ||
element.getUserData(COMMAND_FLAG) == CommandState.Command
fun getCommandState(element: LookupElement): CommandState? {
val flag = element.getUserData(COMMAND_FLAG)
return when {
flag != null -> flag
isCommand(element) -> CommandState.Command
isPostfix(element) -> CommandState.Postfix
else -> null
}
}
fun installCommandState(element: LookupElement, commandState: CommandState?) {
element.putUserData(COMMAND_FLAG, commandState)
}
}
@@ -1,6 +1,7 @@
// Copyright 2000-2026 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.configuration
import com.intellij.codeInsight.completion.NewRdCompletionSupport
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.RoamingType
@@ -118,12 +119,27 @@ internal class AppCommandCompletionSettings(
}
private fun calculateFromRegistry(): Boolean {
// unit tests
if (ApplicationManager.getApplication().isUnitTestMode() &&
Registry.`is`("ide.completion.command.force.enabled")) return true
if (!PlatformUtils.isIntelliJ()) return false
return Registry.`is`("ide.completion.command.force.enabled") ||
(!ApplicationManager.getApplication().isUnitTestMode() &&
Registry.`is`("ide.completion.command.enabled"))
Registry.`is`("ide.completion.command.force.enabled")) {
return true
}
// production
if (
PlatformUtils.isIntelliJ() ||
NewRdCompletionSupport.isFrontendRdCompletionOn() && NewRdCompletionSupport.isFrontendForIntelliJBackend()
) {
if (Registry.`is`("ide.completion.command.force.enabled")) {
return true
}
if (Registry.`is`("ide.completion.command.enabled")) {
return !ApplicationManager.getApplication().isUnitTestMode()
}
}
return false
}
}