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 `<depends>` 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)
This commit is contained in:
Roman Golyshev
2020-02-25 16:44:46 +03:00
committed by Roman Golyshev
parent 4c6ea7c26a
commit f29e665dce
10 changed files with 153 additions and 17 deletions
+1
View File
@@ -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"))
@@ -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=<html>{0} {0, choice, 1#import was|2#imports were} added<p><span><a href='show'>Review Added Imports...</a></span></html>
# Experimental features
experimental.ml.completion=ML Completion for Kotlin
+2
View File
@@ -30,6 +30,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
<depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
<depends>com.intellij.stats.completion</depends>
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
+2
View File
@@ -30,6 +30,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
<depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
<depends>com.intellij.stats.completion</depends>
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
@@ -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<ExperimentalFeature> = 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)
@@ -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
}
@@ -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()
}
}
@@ -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()
}
}
@@ -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()
}
}
@@ -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()
}
}