From f29e665dce9318c1cfe8c5f3f2495323f564f67c Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Tue, 25 Feb 2020 16:44:46 +0300 Subject: [PATCH] Add "ML completion for Kotlin" experimental feature checkbox - This checkbox should be shown only in IDEA >= 193 and should not be shown in AS - ML completion is enabled with `CompletionMLRankingSettings`, which resides in `com.intellij.stats.completion` plugin that is bundled by default - The `` section is required to be able to use classes from this plugin inside Kotlin plugin - `CompletionMLRankingSettings` have package-private setter for enabling ranking completion, so we have to use reflection to enable it (it will probably change in the future) --- idea/build.gradle.kts | 1 + .../kotlin/idea/KotlinBundle.properties | 4 ++ idea/resources/META-INF/plugin.xml | 2 + idea/resources/META-INF/plugin.xml.201 | 2 + .../configuration/ExperimentalFeatures.kt | 56 +++++++++++++------ .../configuration/MLCompletionForKotlin.kt | 41 ++++++++++++++ .../MLCompletionForKotlin.kt.192 | 16 ++++++ .../MLCompletionForKotlin.kt.as34 | 16 ++++++ .../MLCompletionForKotlin.kt.as35 | 16 ++++++ .../MLCompletionForKotlin.kt.as40 | 16 ++++++ 10 files changed, 153 insertions(+), 17 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.192 create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as34 create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as35 create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as40 diff --git a/idea/build.gradle.kts b/idea/build.gradle.kts index 113a1a354ee..0c88433e109 100644 --- a/idea/build.gradle.kts +++ b/idea/build.gradle.kts @@ -87,6 +87,7 @@ dependencies { Platform[193].orHigher { implementation(commonDep("org.jetbrains.intellij.deps.completion", "completion-ranking-kotlin")) + implementation(intellijPluginDep("stats-collector")) } compileOnly(commonDep("org.jetbrains", "markdown")) diff --git a/idea/idea-analysis/resources/org/jetbrains/kotlin/idea/KotlinBundle.properties b/idea/idea-analysis/resources/org/jetbrains/kotlin/idea/KotlinBundle.properties index 04197a1f6b6..1acdc7363ff 100644 --- a/idea/idea-analysis/resources/org/jetbrains/kotlin/idea/KotlinBundle.properties +++ b/idea/idea-analysis/resources/org/jetbrains/kotlin/idea/KotlinBundle.properties @@ -285,3 +285,7 @@ scratch.inlay.output.mode.description=Inlay output mode # Code insight dialog.import.on.paste.title3=Select Import to Remove copy.paste.reference.notification={0} {0, choice, 1#import was|2#imports were} added

Review Added Imports... + +# Experimental features + +experimental.ml.completion=ML Completion for Kotlin \ No newline at end of file diff --git a/idea/resources/META-INF/plugin.xml b/idea/resources/META-INF/plugin.xml index 4e97757eb9f..cec3145bbab 100644 --- a/idea/resources/META-INF/plugin.xml +++ b/idea/resources/META-INF/plugin.xml @@ -30,6 +30,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. Git4Idea org.jetbrains.debugger.streams + com.intellij.stats.completion + diff --git a/idea/resources/META-INF/plugin.xml.201 b/idea/resources/META-INF/plugin.xml.201 index 63cd761d3e2..9f7cf1dc2ac 100644 --- a/idea/resources/META-INF/plugin.xml.201 +++ b/idea/resources/META-INF/plugin.xml.201 @@ -30,6 +30,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. Git4Idea org.jetbrains.debugger.streams + com.intellij.stats.completion + diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt index bf8b0a0420a..24efdd73eb7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.util.registry.Registry import com.intellij.ui.components.JBCheckBox import org.jdesktop.swingx.VerticalLayout import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.PlatformVersion import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService import org.jetbrains.kotlin.idea.util.isDev @@ -18,39 +19,60 @@ import javax.swing.JCheckBox import javax.swing.JPanel object ExperimentalFeatures { - val NewJ2k = ExperimentalFeature( + val NewJ2k = RegistryExperimentalFeature( title = "New Java to Kotlin converter", registryKey = "kotlin.experimental.new.j2k", enabledByDefault = true ) - val NewWizard = ExperimentalFeature( + val NewWizard = object : RegistryExperimentalFeature( title = "New Kotlin project wizard", registryKey = "kotlin.experimental.project.wizard", - enabledByDefault = false, - shouldBeShown = { - val platformVersion = PlatformVersion.getCurrent() ?: return@ExperimentalFeature true - platformVersion.platform != PlatformVersion.Platform.ANDROID_STUDIO - }, - onFeatureStatusChanged = { enabled -> + enabledByDefault = false + ) { + override fun shouldBeShown(): Boolean { + val platformVersion = PlatformVersion.getCurrent() ?: return true + return platformVersion.platform != PlatformVersion.Platform.ANDROID_STUDIO + } + + override fun onFeatureStatusChanged(enabled: Boolean) { WizardStatsService.logWizardStatusChanged(isEnabled = enabled) } - ) + } + + object MLCompletionForKotlinFeature : ExperimentalFeature { + override val title: String + get() = KotlinBundle.message("experimental.ml.completion") + + override fun shouldBeShown(): Boolean = MLCompletionForKotlin.isAvailable + + override var isEnabled: Boolean + get() = MLCompletionForKotlin.isEnabled + set(value) { + MLCompletionForKotlin.isEnabled = value + } + } val allFeatures: List = listOf( NewJ2k, - NewWizard + NewWizard, + MLCompletionForKotlinFeature ) } -class ExperimentalFeature( - val title: String, +interface ExperimentalFeature { + val title: String + var isEnabled: Boolean + fun shouldBeShown(): Boolean = true + fun onFeatureStatusChanged(enabled: Boolean) {} +} + +open class RegistryExperimentalFeature( + override val title: String, private val registryKey: String, - private val enabledByDefault: Boolean, - val shouldBeShown: () -> Boolean = { true }, - val onFeatureStatusChanged: (enabled: Boolean) -> Unit = {} -) { - var isEnabled + private val enabledByDefault: Boolean +) : ExperimentalFeature { + final override var isEnabled get() = Registry.`is`(registryKey, enabledByDefault) set(value) { Registry.get(registryKey).setValue(value) diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt new file mode 100644 index 00000000000..98f56f2a0c6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt @@ -0,0 +1,41 @@ +/* + * 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.idea.configuration + +import com.intellij.completion.settings.CompletionMLRankingSettings +import kotlin.reflect.jvm.isAccessible + +internal object MLCompletionForKotlin { + const val isAvailable: Boolean = true + + var isEnabled: Boolean + get() { + val settings = CompletionMLRankingSettings.getInstance() + return settings.isRankingEnabledHacked && settings.isLanguageEnabled("Kotlin") + } + set(value) { + val settings = CompletionMLRankingSettings.getInstance() + if (value && !settings.isRankingEnabledHacked) { + settings.isRankingEnabledHacked = true + } + + settings.setLanguageEnabled("Kotlin", value) + } +} + +/** + * Setter for this property is package-private, so we have to use reflection to change its value. + */ +private var CompletionMLRankingSettings.isRankingEnabledHacked: Boolean + get() = isRankingEnabled + set(value) { + val rankingEnabledSetter = this::class.members.find { it.name == "setRankingEnabled" } + ?: error("Cannot find 'setRankingEnabled' in class members: ${this::class.members}") + + rankingEnabledSetter.isAccessible = true + rankingEnabledSetter.call(this, value) + rankingEnabledSetter.isAccessible = false + } diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.192 b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.192 new file mode 100644 index 00000000000..360edbe7218 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.192 @@ -0,0 +1,16 @@ +/* + * 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.idea.configuration + +internal object MLCompletionForKotlin { + const val isAvailable: Boolean = false + + override var isEnabled: Boolean + get() = false + set(value) { + throw UnsupportedOperationException() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as34 b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as34 new file mode 100644 index 00000000000..360edbe7218 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as34 @@ -0,0 +1,16 @@ +/* + * 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.idea.configuration + +internal object MLCompletionForKotlin { + const val isAvailable: Boolean = false + + override var isEnabled: Boolean + get() = false + set(value) { + throw UnsupportedOperationException() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as35 b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as35 new file mode 100644 index 00000000000..360edbe7218 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as35 @@ -0,0 +1,16 @@ +/* + * 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.idea.configuration + +internal object MLCompletionForKotlin { + const val isAvailable: Boolean = false + + override var isEnabled: Boolean + get() = false + set(value) { + throw UnsupportedOperationException() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as40 b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as40 new file mode 100644 index 00000000000..360edbe7218 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/MLCompletionForKotlin.kt.as40 @@ -0,0 +1,16 @@ +/* + * 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.idea.configuration + +internal object MLCompletionForKotlin { + const val isAvailable: Boolean = false + + override var isEnabled: Boolean + get() = false + set(value) { + throw UnsupportedOperationException() + } +}