Kotlin 为文件顶级实现IntelliJ Completion Contributor
我正在为IntelliJ开发一个插件,我想使用添加。我正在开发的支持IntelliJ的语言使用OOP,并提供使用典型类(Kotlin 为文件顶级实现IntelliJ Completion Contributor,kotlin,intellij-idea,intellij-plugin,code-completion,Kotlin,Intellij Idea,Intellij Plugin,Code Completion,我正在为IntelliJ开发一个插件,我想使用添加。我正在开发的支持IntelliJ的语言使用OOP,并提供使用典型类(class)和名称空间(namespace)的能力 目前,一切都非常清楚,除了一件事。我无法理解如何仅在文件范围的最高级别调用特定的完成提供程序。下面我举一个例子,清楚地说明目前需要自动完成的地方(伪代码): 在上面的示例中,应该只在第1行和第2行(类范围)上使用完成提供程序,部分在第3行(直到大括号)上以及第6行上使用完成提供程序。简而言之,不应为第4行和第8行调用完成提供程
class
)和名称空间(namespace
)的能力
目前,一切都非常清楚,除了一件事。我无法理解如何仅在文件范围的最高级别调用特定的完成提供程序。下面我举一个例子,清楚地说明目前需要自动完成的地方(伪代码):
在上面的示例中,应该只在第1行和第2行(类范围)上使用完成提供程序,部分在第3行(直到大括号)上以及第6行上使用完成提供程序。简而言之,不应为第4行和第8行调用完成提供程序
请注意,文件可能为空:
1.
2.
在这种情况下,代码完成也应该起作用
下面是实现这一点的样板代码(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"))
}
}
您可以使用
和
将自己的模式条件
添加到元素模式中
假设您有一个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)
})
现在,它只适用于上面示例中的第4行。这是否与BNF声明有关?MyLanguageFile定义是否可能不正确,从而影响代码的完成?我通过添加相关的BNF部分更新了我的问题。是的,这与提供的BNF语法有关。我刚把代码改成
!iStopReplevel(elem)
(否定)和所有的工作就像一个符咒。感谢you@serghei太好了。我添加了另一种方法,希望对您有所帮助
{
psiClassPrefix='My'
// ...
}
File ::= TopStatement*
private TopStatement ::= NamespaceStatement (ClassDefinition | InterfaceDefinition)
NamespaceStatement ::= 'namespace' ComplexId ';' {pin=2}
ClassDefinition ::= ClassModifier? 'class' Id SuperClass? ImplementsList? ClassBody {pin=3}
// ...
fun isTopLevel(elem: PsiElement): Boolean = elem.parent is MyLanguageFile
val context = PlatformPatterns
.psiElement()
.with(object : PatternCondition<PsiElement>("toplevel") {
override fun accepts(elem: PsiElement, context: ProcessingContext?) = isTopLevel(elem)
})
context = psiElement()
.andOr(
psiElement().withElementType(NAMESPACE_NAME),
psiElement().withElementType(CLASS_NAME),
//other top level stuff
)