Show experimental features panel only for non-stable plugin versions

Also, use registry as backend for features settings
This commit is contained in:
Ilya Kirillov
2020-02-12 17:18:00 +03:00
parent b045adf83a
commit 531a63bd19
12 changed files with 138 additions and 70 deletions
@@ -12,9 +12,9 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ui.configuration.ModulesProvider
import com.intellij.openapi.ui.Messages
import com.intellij.util.SystemProperties
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.framework.KotlinModuleSettingStep
import org.jetbrains.kotlin.idea.framework.KotlinTemplatesFactory
import org.jetbrains.kotlin.idea.projectWizard.NewProjectWizardService
import org.jetbrains.kotlin.idea.projectWizard.ProjectCreationStats
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService
@@ -61,7 +61,7 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() {
private const val INVALID_PROJECT_NAME_MESSAGE = "Invalid project name"
}
override fun isAvailable(): Boolean = NewProjectWizardService.isEnabled
override fun isAvailable(): Boolean = ExperimentalFeatures.NewWizard.isEnabled
private var wizardContext: WizardContext? = null
@@ -11,11 +11,11 @@ import com.intellij.openapi.application.runWriteAction
import com.intellij.psi.PsiDocumentManager
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest
import org.jetbrains.kotlin.idea.conversion.copy.ConvertJavaCopyPasteProcessor
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.testFramework.commitAllDocuments
import org.jetbrains.kotlin.j2k.J2kConverterExtension
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
@@ -38,7 +38,7 @@ abstract class AbstractPerformanceJavaToKotlinCopyPasteConversionTest(private va
override fun setUp() {
super.setUp()
J2kConverterExtension.isNewJ2k = newJ2K
ExperimentalFeatures.NewJ2k.isEnabled = newJ2K
val index = j2kIndex()
if (!warmedUp[index]) {
@@ -131,6 +131,16 @@
description="Allow a trailing comma on call-site"
defaultValue="false"
restartRequired="false"/>
<registryKey key="kotlin.experimental.new.j2k"
description="New Java to Kotlin Converter"
defaultValue="true"
restartRequired="false"/>
<registryKey key="kotlin.experimental.project.wizard"
description="New Experimental Project Wizard"
defaultValue="false"
restartRequired="false"/>
<fileEditorProvider implementation="org.jetbrains.kotlin.idea.scratch.ui.KtScratchFileEditorProvider"/>
<moduleBuilder builderClass="org.jetbrains.kotlin.tools.projectWizard.wizard.NewProjectWizardModuleBuilder"/>
@@ -47,6 +47,7 @@ import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
@@ -129,7 +130,7 @@ class JavaToKotlinAction : AnAction() {
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
) else J2kConverterExtension.extension().createJavaToKotlinConverter(
) else J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).createJavaToKotlinConverter(
project,
module,
ConverterSettings.defaultSettings,
@@ -138,7 +139,7 @@ class JavaToKotlinAction : AnAction() {
converterResult = converter.filesToKotlin(
javaFiles,
if (forceUsingOldJ2k) J2kPostProcessor(formatCode = true)
else J2kConverterExtension.extension().createPostProcessor(formatCode = true),
else J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).createPostProcessor(formatCode = true),
progress = ProgressManager.getInstance().progressIndicator!!
)
}
@@ -153,7 +154,7 @@ class JavaToKotlinAction : AnAction() {
logJ2kConversionStatistics(
ConversionType.FILES,
J2kConverterExtension.isNewJ2k,
ExperimentalFeatures.NewJ2k.isEnabled,
conversionTime,
linesCount,
javaFiles.size
@@ -232,7 +233,7 @@ class JavaToKotlinAction : AnAction() {
.showInCenterOf(statusBar.component)
}
if (!J2kConverterExtension.extension().doCheckBeforeConversion(project, module)) return
if (!J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).doCheckBeforeConversion(project, module)) return
val firstSyntaxError = javaFiles.asSequence().map { PsiTreeUtil.findChildOfType(it, PsiErrorElement::class.java) }.firstOrNull()
@@ -0,0 +1,100 @@
/*
* 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.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.PlatformVersion
import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService
import org.jetbrains.kotlin.idea.util.isDev
import org.jetbrains.kotlin.idea.util.isEap
import org.jetbrains.kotlin.idea.util.isSnapshot
import javax.swing.JCheckBox
import javax.swing.JPanel
object ExperimentalFeatures {
val NewJ2k = ExperimentalFeature(
title = "New Java to Kotlin Converter",
registryKey = "kotlin.experimental.new.j2k",
enabledByDefault = true
)
val NewWizard = ExperimentalFeature(
title = "New Experimental 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 ->
WizardStatsService.logWizardStatusChanged(isEnabled = enabled)
}
)
val allFeatures: List<ExperimentalFeature> = listOf(
NewJ2k,
NewWizard
)
}
class ExperimentalFeature(
val title: String,
private val registryKey: String,
private val enabledByDefault: Boolean,
val shouldBeShown: () -> Boolean = { true },
val onFeatureStatusChanged: (enabled: Boolean) -> Unit = {}
) {
var isEnabled
get() = Registry.`is`(registryKey, enabledByDefault)
set(value) {
Registry.get(registryKey).setValue(value)
}
}
class ExperimentalFeaturesPanel : JPanel(VerticalLayout(5)) {
private val featuresWithCheckboxes = ExperimentalFeatures.allFeatures.map { feature ->
FeatureWithCheckbox(
feature,
JBCheckBox(feature.title, feature.isEnabled)
)
}
init {
featuresWithCheckboxes.forEach { (feature, checkBox) ->
if (feature.shouldBeShown()) {
add(checkBox)
}
}
}
private data class FeatureWithCheckbox(
val feature: ExperimentalFeature,
val checkbox: JCheckBox
)
fun isModified() = featuresWithCheckboxes.any { (feature, checkBox) ->
feature.isEnabled != checkBox.isSelected
}
fun applySelectedChanges() {
featuresWithCheckboxes.forEach { (feature, checkBox) ->
if (feature.isEnabled != checkBox.isSelected) {
feature.isEnabled = checkBox.isSelected
feature.onFeatureStatusChanged(checkBox.isSelected)
}
}
}
companion object {
fun shouldBeShown(): Boolean {
val version = KotlinCompilerVersion.VERSION
return isEap(version) || isDev(version) || isSnapshot(version)
}
}
}
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.idea.KotlinPluginUpdater
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.PluginUpdateStatus
import org.jetbrains.kotlin.idea.configuration.ui.KotlinLanguageConfigurationForm
import org.jetbrains.kotlin.idea.projectWizard.NewProjectWizardService
import org.jetbrains.kotlin.j2k.J2kConverterExtension
import javax.swing.JComponent
class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScroll {
@@ -65,14 +63,12 @@ class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScrol
override fun getDisplayName(): String = "Kotlin"
override fun isModified() =
form.useNewJ2kCheckBox.isSelected != J2kConverterExtension.isNewJ2k
|| form.useNewProjectWizardCheckBox.isSelected != NewProjectWizardService.isEnabled
form.experimentalFeaturesPanel.isModified()
override fun apply() {
// Selected channel is now saved automatically
J2kConverterExtension.isNewJ2k = form.useNewJ2kCheckBox.isSelected
NewProjectWizardService.isEnabled = form.useNewProjectWizardCheckBox.isSelected
form.experimentalFeaturesPanel.applySelectedChanges()
}
private fun setInstalledVersion(installedVersion: String?, installingStatus: String?) {
@@ -81,8 +77,6 @@ class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScrol
}
override fun createComponent(): JComponent? {
form.useNewJ2kCheckBox.isSelected = J2kConverterExtension.isNewJ2k
form.useNewProjectWizardCheckBox.isSelected = NewProjectWizardService.isEnabled
form.updateCheckProgressIcon.suspend()
form.updateCheckProgressIcon.setPaintPassiveIcon(false)
@@ -150,7 +150,7 @@
</component>
</children>
</grid>
<grid id="15a75" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="15a75" binding="experimentalFeaturesPanelContainer" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="6" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
@@ -161,22 +161,17 @@
</clientProperties>
<border type="etched" title="Experimental Features"/>
<children>
<component id="d2573" class="javax.swing.JCheckBox" binding="useNewJ2kCheckBox" default-binding="true">
<component id="31057" class="org.jetbrains.kotlin.idea.configuration.ExperimentalFeaturesPanel" binding="experimentalFeaturesPanel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Use New Java to Kotlin Converter"/>
</properties>
<properties/>
</component>
<component id="8a05f" class="javax.swing.JCheckBox" binding="useNewProjectWizardCheckBox">
<hspacer id="4e58d">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Use New Project Wizard"/>
</properties>
</component>
</hspacer>
</children>
</grid>
<vspacer id="73440">
@@ -10,6 +10,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.ui.AsyncProcessIcon;
import org.jetbrains.kotlin.idea.KotlinPluginUtil;
import org.jetbrains.kotlin.idea.PlatformVersion;
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeaturesPanel;
import org.jetbrains.kotlin.idea.util.VersioningKt;
import javax.swing.*;
@@ -28,14 +29,12 @@ public class KotlinLanguageConfigurationForm {
private JTextPane currentVersion;
private JPanel bundledCompilerVersionPanel;
private JTextPane compilerVersion;
public JCheckBox useNewJ2kCheckBox;
public JCheckBox useNewProjectWizardCheckBox;
public ExperimentalFeaturesPanel experimentalFeaturesPanel;
private JPanel experimentalFeaturesPanelContainer;
public KotlinLanguageConfigurationForm() {
showVerifierDisabledStatus();
useNewProjectWizardCheckBox.setVisible(!isAndroidStudio());
experimentalFeaturesPanelContainer.setVisible(ExperimentalFeaturesPanel.Companion.shouldBeShown());
String pluginVersion = KotlinPluginUtil.getPluginVersion();
if (KotlinPluginUtil.isPatched()) {
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor
import org.jetbrains.kotlin.idea.codeInsight.KotlinReferenceData
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.core.util.start
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
@@ -190,7 +191,7 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor<TextBlockTransferab
}
logJ2kConversionStatistics(
ConversionType.PSI_EXPRESSION,
J2kConverterExtension.isNewJ2k,
ExperimentalFeatures.NewJ2k.isEnabled,
conversionTime,
dataForConversion.elementsAndTexts.linesCount(),
filesCount = 1
@@ -347,7 +348,7 @@ fun ElementAndTextList.linesCount() =
fun checkUseNewJ2k(targetFile: KtFile): Boolean {
if (targetFile is KtCodeFragment) return false
return J2kConverterExtension.isNewJ2k
return ExperimentalFeatures.NewJ2k.isEnabled
}
fun runPostProcessing(
@@ -1,22 +0,0 @@
/*
* 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.projectWizard
import com.intellij.ide.util.PropertiesComponent
object NewProjectWizardService {
private const val optionName = "kotlin.experimental.project.wizard"
private const val enabledByDefault = false
var isEnabled
get() = PropertiesComponent.getInstance().getBoolean(optionName, enabledByDefault)
set(value) {
if (value != isEnabled) {
WizardStatsService.logWizardStatusChanged(isEnabled = value)
}
PropertiesComponent.getInstance().setValue(optionName, value, enabledByDefault)
}
}
@@ -5,15 +5,14 @@
package org.jetbrains.kotlin.idea.conversion.copy
import com.intellij.openapi.util.registry.Registry
import org.jetbrains.kotlin.idea.AbstractCopyPasteTest
import org.jetbrains.kotlin.j2k.J2kConverterExtension
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
abstract class AbstractJ2kCopyPasteTest : AbstractCopyPasteTest() {
protected open fun isNewJ2K(): Boolean = false
override fun setUp() {
super.setUp()
J2kConverterExtension.isNewJ2k = isNewJ2K()
ExperimentalFeatures.NewJ2k.isEnabled = isNewJ2K()
}
}
@@ -30,18 +30,9 @@ abstract class J2kConverterExtension : AbstractExtensionPointBean() {
): WithProgressProcessor
companion object {
private const val newJ2kByDefault = true
private const val optionName = "kotlin.use.new.j2k"
var isNewJ2k
get() = PropertiesComponent.getInstance().getBoolean(optionName, newJ2kByDefault)
set(value) {
PropertiesComponent.getInstance().setValue(optionName, value, newJ2kByDefault)
}
val EP_NAME = ExtensionPointName.create<J2kConverterExtension>("org.jetbrains.kotlin.j2kConverterExtension")
fun extension(useNewJ2k: Boolean = isNewJ2k): J2kConverterExtension =
fun extension(useNewJ2k: Boolean): J2kConverterExtension =
EP_NAME.extensions.first { it.isNewJ2k == useNewJ2k }
}
}