为文件顶层实现 IntelliJ Completion Contributor
Implementing IntelliJ Completion Contributor for the file top level
我正在开发 custom language plugin for IntelliJ and I want to add code completion support using the CompletionContributor。我正在开发支持 IntelliJ 的语言使用 OOP,并提供使用典型 classes (class
) 和命名空间 (namespace
).
的能力
此刻,除了一件事,一切都无比清晰。我无法理解如何在文件范围的最高级别调用特定的完成提供程序 only。下面我举个例子来说明一下目前需要自动补全的地方(伪代码):
1. namespace Foo;
2.
3. class Test {
4.
5. }
6.
7. function foo() {
8.
9. }
在上面的示例中,完成提供程序应该 仅在第 1 行和第 2 行(class 范围) 上使用,部分在第 3 行上使用(直到花括号),以及第 6 行。简而言之,不应为第 4 行和第 8 行调用完成提供程序 。
请注意文件可能为空:
1.
2.
在这种情况下,代码补全 应该也可以工作 。
Bellow 是实现此目的的样板代码 (Kotlin)。
贡献者:
// com.some.lang.core.completion.MyCompletionContributor
package com.some.lang.core.completion
import com.intellij.codeInsight.completion.CompletionContributor
import com.some.lang.core.completion.providers.FileScopeCompletionProvider
class MyCompletionContributor : CompletionContributor() {
private val providers = listOf(
FileScopeCompletionProvider
)
init {
providers.forEach { extend(it) }
}
private fun extend(provider: MyCompletionProvider) {
extend(provider.type, provider.context, provider)
}
}
抽象提供者:
// package com.some.lang.core.completion.MyCompletionProvider
package com.some.lang.core.completion
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.patterns.ElementPattern
import com.intellij.psi.PsiElement
abstract class MyCompletionProvider : CompletionProvider<CompletionParameters>() {
abstract val context: ElementPattern<out PsiElement>
open val type: CompletionType = CompletionType.BASIC
}
文件范围提供者:
// package com.some.lang.core.completion.providers.FileScopeCompletionProvider
package com.some.lang.core.completion.providers
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import com.some.lang.core.Language
import com.some.lang.core.completion.MyCompletionProvider
object FileScopeCompletionProvider : MyCompletionProvider() {
override val context: ElementPattern<PsiElement>
get() = PlatformPatterns.psiElement().withLanguage(Language)
override fun addCompletions(
parameters: CompletionParameters,
processingContext: ProcessingContext,
result: CompletionResultSet
) {
result.addElement(LookupElementBuilder.create("Hello"))
}
}
当然,这段代码并不能满足需要。但是,它确实显示了我使用的一般设计。我确定我需要修复以下几行:
override val context: ElementPattern<PsiElement>
get() = PlatformPatterns.psiElement().withLanguage(Language)
而且主要问题是我不明白怎么做。
更新:
相关 BNF 部分:
{
psiClassPrefix='My'
// ...
}
File ::= TopStatement*
private TopStatement ::= NamespaceStatement (ClassDefinition | InterfaceDefinition)
NamespaceStatement ::= 'namespace' ComplexId ';' {pin=2}
ClassDefinition ::= ClassModifier? 'class' Id SuperClass? ImplementsList? ClassBody {pin=3}
// ...
您可以使用 with
将您自己的 PatternCondition
添加到您的元素模式中。
假设您有一个 isTopLevel
函数定义如下:
fun isTopLevel(elem: PsiElement): Boolean = elem.parent is MyLanguageFile
您可以使用此 ElementPattern
使您的完成仅对顶级元素可用。
val context = PlatformPatterns
.psiElement()
.with(object : PatternCondition<PsiElement>("toplevel") {
override fun accepts(elem: PsiElement, context: ProcessingContext?) = isTopLevel(elem)
})
编辑:您还可以使用 withElementType
来控制补全将应用于哪些元素类型。例如:
context = psiElement()
.andOr(
psiElement().withElementType(NAMESPACE_NAME),
psiElement().withElementType(CLASS_NAME),
//other top level stuff
)
我正在开发 custom language plugin for IntelliJ and I want to add code completion support using the CompletionContributor。我正在开发支持 IntelliJ 的语言使用 OOP,并提供使用典型 classes (class
) 和命名空间 (namespace
).
此刻,除了一件事,一切都无比清晰。我无法理解如何在文件范围的最高级别调用特定的完成提供程序 only。下面我举个例子来说明一下目前需要自动补全的地方(伪代码):
1. namespace Foo;
2.
3. class Test {
4.
5. }
6.
7. function foo() {
8.
9. }
在上面的示例中,完成提供程序应该 仅在第 1 行和第 2 行(class 范围) 上使用,部分在第 3 行上使用(直到花括号),以及第 6 行。简而言之,不应为第 4 行和第 8 行调用完成提供程序 。
请注意文件可能为空:
1.
2.
在这种情况下,代码补全 应该也可以工作 。
Bellow 是实现此目的的样板代码 (Kotlin)。
贡献者:
// com.some.lang.core.completion.MyCompletionContributor
package com.some.lang.core.completion
import com.intellij.codeInsight.completion.CompletionContributor
import com.some.lang.core.completion.providers.FileScopeCompletionProvider
class MyCompletionContributor : CompletionContributor() {
private val providers = listOf(
FileScopeCompletionProvider
)
init {
providers.forEach { extend(it) }
}
private fun extend(provider: MyCompletionProvider) {
extend(provider.type, provider.context, provider)
}
}
抽象提供者:
// package com.some.lang.core.completion.MyCompletionProvider
package com.some.lang.core.completion
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.patterns.ElementPattern
import com.intellij.psi.PsiElement
abstract class MyCompletionProvider : CompletionProvider<CompletionParameters>() {
abstract val context: ElementPattern<out PsiElement>
open val type: CompletionType = CompletionType.BASIC
}
文件范围提供者:
// package com.some.lang.core.completion.providers.FileScopeCompletionProvider
package com.some.lang.core.completion.providers
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import com.some.lang.core.Language
import com.some.lang.core.completion.MyCompletionProvider
object FileScopeCompletionProvider : MyCompletionProvider() {
override val context: ElementPattern<PsiElement>
get() = PlatformPatterns.psiElement().withLanguage(Language)
override fun addCompletions(
parameters: CompletionParameters,
processingContext: ProcessingContext,
result: CompletionResultSet
) {
result.addElement(LookupElementBuilder.create("Hello"))
}
}
当然,这段代码并不能满足需要。但是,它确实显示了我使用的一般设计。我确定我需要修复以下几行:
override val context: ElementPattern<PsiElement>
get() = PlatformPatterns.psiElement().withLanguage(Language)
而且主要问题是我不明白怎么做。
更新:
相关 BNF 部分:
{
psiClassPrefix='My'
// ...
}
File ::= TopStatement*
private TopStatement ::= NamespaceStatement (ClassDefinition | InterfaceDefinition)
NamespaceStatement ::= 'namespace' ComplexId ';' {pin=2}
ClassDefinition ::= ClassModifier? 'class' Id SuperClass? ImplementsList? ClassBody {pin=3}
// ...
您可以使用 with
将您自己的 PatternCondition
添加到您的元素模式中。
假设您有一个 isTopLevel
函数定义如下:
fun isTopLevel(elem: PsiElement): Boolean = elem.parent is MyLanguageFile
您可以使用此 ElementPattern
使您的完成仅对顶级元素可用。
val context = PlatformPatterns
.psiElement()
.with(object : PatternCondition<PsiElement>("toplevel") {
override fun accepts(elem: PsiElement, context: ProcessingContext?) = isTopLevel(elem)
})
编辑:您还可以使用 withElementType
来控制补全将应用于哪些元素类型。例如:
context = psiElement()
.andOr(
psiElement().withElementType(NAMESPACE_NAME),
psiElement().withElementType(CLASS_NAME),
//other top level stuff
)