Я разрабатываю плагин настраиваемый язык для IntelliJ и хочу добавить поддержку завершения кода , используя CompletionContributor . Язык, который я разрабатываю для поддержки IntelliJ, использует OOP и предоставляет возможность использовать типичные классы (class
) и пространства имен (namespace
).
На данный момент все предельно ясно, кроме для одной вещи. Я не могу понять, как вызвать специфику c поставщика завершения только на самом высоком уровне области видимости файла. Ниже я привожу пример, чтобы наглядно показать место, где в данный момент требуется автозаполнение (псевдокод):
1. namespace Foo;
2.
3. class Test {
4.
5. }
6.
7. function foo() {
8.
9. }
В приведенном выше примере следует использовать поставщика завершения только в строках 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"))
}
}
Конечно, этот код не делает того, что нужно. Тем не менее, он показывает общий дизайн, который я использую. Я уверен, что мне нужно исправить следующие строки:
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}
// ...