Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 为文件顶级实现IntelliJ Completion Contributor_Kotlin_Intellij Idea_Intellij Plugin_Code Completion - Fatal编程技术网

Kotlin 为文件顶级实现IntelliJ Completion Contributor

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行调用完成提供程

我正在为IntelliJ开发一个插件,我想使用添加。我正在开发的支持IntelliJ的语言使用OOP,并提供使用典型类(
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
  )