Add scripting REPL completion options

nameFilter - way of filtering descriptors by their names;
filterOutShadowedDescriptors - if true, filters out descriptors
shadowed by descriptors in latter-compiled snippets. May slow down
completion performance.
This commit is contained in:
Ilya Muradyan
2020-05-13 03:19:47 +03:00
committed by Ilya Chernikov
parent 0ab9b3639b
commit bbe00b2fdc
4 changed files with 182 additions and 52 deletions
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.scripting.ide_services.compiler
import kotlin.script.experimental.api.ScriptCompilationConfigurationKeys
import kotlin.script.experimental.util.PropertiesCollection
interface ReplCompletionOptionsKeys
open class ReplCompletionOptionsBuilder : PropertiesCollection.Builder(), ReplCompletionOptionsKeys {
companion object : ReplCompletionOptionsKeys
}
fun ReplCompletionOptionsBuilder.filterOutShadowedDescriptors(value: Boolean) {
this[filterOutShadowedDescriptors] = value
}
fun ReplCompletionOptionsBuilder.nameFilter(value: (String, String) -> Boolean) {
this[nameFilter] = value
}
val ReplCompletionOptionsKeys.filterOutShadowedDescriptors by PropertiesCollection.key(true)
val ReplCompletionOptionsKeys.nameFilter
by PropertiesCollection.key<(String, String) -> Boolean>({ name, namePart -> name.startsWith(namePart) })
@Suppress("unused")
val ScriptCompilationConfigurationKeys.completion
get() = ReplCompletionOptionsBuilder()
@@ -54,7 +54,8 @@ class KJvmReplCompilerWithIdeServices(hostConfiguration: ScriptingHostConfigurat
bindingContext,
resolutionFacade,
moduleDescriptor,
cursorAbs
cursorAbs,
configuration
).asSuccess(messageCollector.diagnostics)
}
}
@@ -30,11 +30,15 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope.Companion.ALL_NAME_FILTER
import org.jetbrains.kotlin.scripting.ide_services.compiler.completion
import org.jetbrains.kotlin.scripting.ide_services.compiler.filterOutShadowedDescriptors
import org.jetbrains.kotlin.scripting.ide_services.compiler.nameFilter
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.asFlexibleType
import org.jetbrains.kotlin.types.isFlexible
import java.io.File
import java.util.*
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.SourceCodeCompletionVariant
fun getKJvmCompletion(
@@ -42,8 +46,16 @@ fun getKJvmCompletion(
bindingContext: BindingContext,
resolutionFacade: KotlinResolutionFacadeForRepl,
moduleDescriptor: ModuleDescriptor,
cursor: Int
) = KJvmReplCompleter(ktScript, bindingContext, resolutionFacade, moduleDescriptor, cursor).getCompletion()
cursor: Int,
configuration: ScriptCompilationConfiguration
) = KJvmReplCompleter(
ktScript,
bindingContext,
resolutionFacade,
moduleDescriptor,
cursor,
configuration
).getCompletion()
// Insert a constant string right after a cursor position to make this identifiable as a simple reference
// For example, code line
@@ -60,7 +72,8 @@ private class KJvmReplCompleter(
private val bindingContext: BindingContext,
private val resolutionFacade: KotlinResolutionFacadeForRepl,
private val moduleDescriptor: ModuleDescriptor,
private val cursor: Int
private val cursor: Int,
private val configuration: ScriptCompilationConfiguration
) {
private fun getElementAt(cursorPos: Int): PsiElement? {
@@ -72,6 +85,9 @@ private class KJvmReplCompleter(
}
fun getCompletion() = sequence<SourceCodeCompletionVariant> gen@{
val filterOutShadowedDescriptors = configuration[ScriptCompilationConfiguration.completion.filterOutShadowedDescriptors]!!
val nameFilter = configuration[ScriptCompilationConfiguration.completion.nameFilter]!!
val element = getElementAt(cursor)
var descriptors: Collection<DeclarationDescriptor>? = null
@@ -109,9 +125,9 @@ private class KJvmReplCompleter(
).getReferenceVariants(
simpleExpression,
DescriptorKindFilter.ALL,
{ name: Name -> !name.isSpecial && name.identifier.startsWith(prefix) },
{ name: Name -> !name.isSpecial && nameFilter(name.identifier, prefix) },
filterOutJavaGettersAndSetters = true,
filterOutShadowed = false, // setting to true makes it slower up to 4 times
filterOutShadowed = filterOutShadowedDescriptors, // setting to true makes it slower up to 4 times
excludeNonInitializedVariable = true,
useReceiverType = null
)
@@ -177,7 +193,8 @@ private class KJvmReplCompleter(
receiverExpression,
CallTypeAndReceiver.DOT(receiverExpression),
DescriptorKindFilter.ALL,
ALL_NAME_FILTER
ALL_NAME_FILTER,
filterOutShadowed = filterOutShadowedDescriptors,
)
}
} else {
@@ -223,7 +240,7 @@ private class KJvmReplCompleter(
.forEach {
val descriptor = it.first
val (rawName, presentableText, tailText, completionText) = it.second
if (rawName.startsWith(prefix)) {
if (nameFilter(rawName, prefix)) {
val fullName: String =
formatName(
presentableText