Kotlin Facet: Add "Use project settings" option

This commit is contained in:
Alexey Sedunov
2016-12-13 16:38:40 +03:00
parent 4ed030d7c5
commit eac0c9b2ed
11 changed files with 153 additions and 45 deletions
@@ -67,7 +67,7 @@ enum class LanguageVersion(val versionString: String) : DescriptionAware {
companion object {
@JvmStatic
fun fromVersionString(str: String) = values().find { it.versionString == str }
fun fromVersionString(str: String?) = values().find { it.versionString == str }
@JvmStatic
fun fromFullVersionString(str: String) = str.split(".", "-").let { if (it.size >= 2) fromVersionString("${it[0]}.${it[1]}") else null }
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,15 +30,14 @@ public abstract class BaseKotlinCompilerSettings<T> implements PersistentStateCo
public static final String KOTLIN_COMPILER_SETTINGS_PATH = PROJECT_CONFIG_DIR + "/" + SettingConstants.KOTLIN_COMPILER_SETTINGS_FILE;
private static final SkipDefaultValuesSerializationFilters SKIP_DEFAULT_VALUES = new SkipDefaultValuesSerializationFilters();
@NotNull
private T settings;
protected BaseKotlinCompilerSettings() {
//noinspection AbstractMethodCallInConstructor
this.settings = createSettings();
}
@NotNull
private T settings;
@NotNull
public T getSettings() {
return settings;
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,24 +22,23 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
import static org.jetbrains.kotlin.config.SettingConstants.KOTLIN_COMMON_COMPILER_ARGUMENTS_SECTION;
import static org.jetbrains.kotlin.idea.compiler.configuration.BaseKotlinCompilerSettings.KOTLIN_COMPILER_SETTINGS_PATH;
@State(
name = KOTLIN_COMMON_COMPILER_ARGUMENTS_SECTION,
storages = {
@Storage(file = StoragePathMacros.PROJECT_FILE),
@Storage(file = KOTLIN_COMPILER_SETTINGS_PATH, scheme = StorageScheme.DIRECTORY_BASED)
@Storage(file = BaseKotlinCompilerSettings.KOTLIN_COMPILER_SETTINGS_PATH, scheme = StorageScheme.DIRECTORY_BASED)
}
)
public class KotlinCommonCompilerArgumentsHolder extends BaseKotlinCompilerSettings<CommonCompilerArguments> {
public static KotlinCommonCompilerArgumentsHolder getInstance(Project project) {
return ServiceManager.getService(project, KotlinCommonCompilerArgumentsHolder.class);
}
@NotNull
@Override
protected CommonCompilerArguments createSettings() {
return new CommonCompilerArguments.DummyImpl();
}
public static KotlinCommonCompilerArgumentsHolder getInstance(Project project) {
return ServiceManager.getService(project, KotlinCommonCompilerArgumentsHolder.class);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,13 +33,13 @@ import static org.jetbrains.kotlin.config.SettingConstants.KOTLIN_COMPILER_SETTI
)
public class KotlinCompilerSettings extends BaseKotlinCompilerSettings<CompilerSettings> {
public static KotlinCompilerSettings getInstance(Project project) {
return ServiceManager.getService(project, KotlinCompilerSettings.class);
}
@NotNull
@Override
protected CompilerSettings createSettings() {
return new CompilerSettings();
}
public static KotlinCompilerSettings getInstance(Project project) {
return ServiceManager.getService(project, KotlinCompilerSettings.class);
}
}
@@ -19,12 +19,15 @@ package org.jetbrains.kotlin.idea.project
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectFileIndex
import com.sampullara.cli.Argument
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -38,29 +41,60 @@ private val multiPlatformProjectsArg: String by lazy {
"-" + CommonCompilerArguments::multiPlatform.annotations.filterIsInstance<Argument>().single().value
}
val Project.languageVersionSettings: LanguageVersionSettings
get() {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion = LanguageVersion.fromVersionString(arguments.languageVersion) ?: LanguageVersion.LATEST
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
val extraLanguageFeatures = getExtraLanguageFeatures(
TargetPlatformKind.Default,
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
compilerSettings
)
return LanguageVersionSettingsImpl(
languageVersion,
apiVersion,
extraLanguageFeatures
)
}
val Module.languageVersionSettings: LanguageVersionSettings
get() {
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getSettings(this)
if (facetSettings.useProjectSettings) return project.languageVersionSettings
val versionInfo = facetSettings.versionInfo
val languageVersion = versionInfo.languageLevel ?: LanguageVersion.LATEST
val apiVersion = versionInfo.apiLevel ?: languageVersion
val extraLanguageFeatures = mutableListOf<LanguageFeature>().apply {
when (facetSettings.compilerInfo.coroutineSupport) {
CoroutineSupport.ENABLED -> {}
CoroutineSupport.ENABLED_WITH_WARNING -> add(LanguageFeature.WarnOnCoroutines)
CoroutineSupport.DISABLED -> add(LanguageFeature.ErrorOnCoroutines)
}
if (versionInfo.targetPlatformKind == TargetPlatformKind.Default ||
// TODO: this is a dirty hack, parse arguments correctly here
facetSettings.compilerInfo.compilerSettings?.additionalArguments?.contains(multiPlatformProjectsArg) == true)
add(LanguageFeature.MultiPlatformProjects)
}
val extraLanguageFeatures = getExtraLanguageFeatures(
versionInfo.targetPlatformKind ?: TargetPlatformKind.Default,
facetSettings.compilerInfo.coroutineSupport,
facetSettings.compilerInfo.compilerSettings
)
return LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion), extraLanguageFeatures)
}
private fun getExtraLanguageFeatures(
targetPlatformKind: TargetPlatformKind<*>,
coroutineSupport: CoroutineSupport,
compilerSettings: CompilerSettings?
): List<LanguageFeature> {
return mutableListOf<LanguageFeature>().apply {
when (coroutineSupport) {
CoroutineSupport.ENABLED -> {}
CoroutineSupport.ENABLED_WITH_WARNING -> add(LanguageFeature.WarnOnCoroutines)
CoroutineSupport.DISABLED -> add(LanguageFeature.ErrorOnCoroutines)
}
if (targetPlatformKind == TargetPlatformKind.Default ||
// TODO: this is a dirty hack, parse arguments correctly here
compilerSettings?.additionalArguments?.contains(multiPlatformProjectsArg) == true) {
add(LanguageFeature.MultiPlatformProjects)
}
}
}
val KtElement.languageVersionSettings: LanguageVersionSettings
get() {
if (ServiceManager.getService(containingKtFile.project, ProjectFileIndex::class.java) == null) {
@@ -113,6 +113,8 @@ class KotlinFacetSettings {
val DEFAULT_VERSION = 0
}
var useProjectSettings: Boolean = false
var versionInfo = KotlinVersionInfo()
var compilerInfo = KotlinCompilerInfo()
}
@@ -24,11 +24,14 @@ import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.RawCommandLineEditor;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,6 +43,7 @@ import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.idea.KotlinBundle;
import org.jetbrains.kotlin.idea.PluginStartupComponent;
import org.jetbrains.kotlin.idea.facet.DescriptionListCellRenderer;
import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
@@ -64,7 +68,7 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
@Nullable
private final KotlinCompilerWorkspaceSettings compilerWorkspaceSettings;
private final Project project;
private final boolean showLanguageVersion;
private final boolean isProjectSettings;
private JPanel contentPane;
private JCheckBox generateNoWarningsCheckBox;
private RawCommandLineEditor additionalArgsOptionsField;
@@ -98,7 +102,7 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
CompilerSettings compilerSettings,
@Nullable KotlinCompilerWorkspaceSettings compilerWorkspaceSettings,
@Nullable K2JVMCompilerArguments k2jvmCompilerArguments,
boolean showLanguageVersion
boolean isProjectSettings
) {
this.project = project;
this.commonCompilerArguments = commonCompilerArguments;
@@ -106,9 +110,9 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
this.compilerSettings = compilerSettings;
this.compilerWorkspaceSettings = compilerWorkspaceSettings;
this.k2jvmCompilerArguments = k2jvmCompilerArguments;
this.showLanguageVersion = showLanguageVersion;
this.isProjectSettings = isProjectSettings;
if (!showLanguageVersion) {
if (!isProjectSettings) {
languageVersionPanel.setVisible(false);
}
@@ -247,7 +251,7 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
@Override
public boolean isModified() {
return ComparingUtils.isModified(generateNoWarningsCheckBox, commonCompilerArguments.suppressWarnings) ||
(showLanguageVersion && !getSelectedLanguageVersion().equals(getLanguageVersionOrDefault(commonCompilerArguments.languageVersion))) ||
(isProjectSettings && !getSelectedLanguageVersion().equals(getLanguageVersionOrDefault(commonCompilerArguments.languageVersion))) ||
!coroutineSupportComboBox.getSelectedItem().equals(CoroutineSupport.byCompilerArguments(commonCompilerArguments)) ||
ComparingUtils.isModified(additionalArgsOptionsField, compilerSettings.getAdditionalArguments()) ||
ComparingUtils.isModified(scriptTemplatesField, compilerSettings.getScriptTemplates()) ||
@@ -284,8 +288,20 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
@Override
public void apply() throws ConfigurationException {
commonCompilerArguments.suppressWarnings = generateNoWarningsCheckBox.isSelected();
if (showLanguageVersion) {
if (isProjectSettings) {
boolean languageVersionChanged = commonCompilerArguments.languageVersion != getSelectedLanguageVersion();
commonCompilerArguments.languageVersion = getSelectedLanguageVersion();
if (languageVersionChanged) {
ApplicationUtilsKt.runWriteAction(
new Function0<Object>() {
@Override
public Object invoke() {
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.INSTANCE, false, true);
return null;
}
}
);
}
}
CoroutineSupport coroutineSupport = (CoroutineSupport) coroutineSupportComboBox.getSelectedItem();
commonCompilerArguments.coroutinesEnable = coroutineSupport == CoroutineSupport.ENABLED;
@@ -322,7 +338,7 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
@Override
public void reset() {
generateNoWarningsCheckBox.setSelected(commonCompilerArguments.suppressWarnings);
if (showLanguageVersion) {
if (isProjectSettings) {
languageVersionComboBox.setSelectedItem(getLanguageVersionOrDefault(commonCompilerArguments.languageVersion));
}
coroutineSupportComboBox.setSelectedItem(CoroutineSupport.byCompilerArguments(commonCompilerArguments));
@@ -363,4 +379,8 @@ public class KotlinCompilerConfigurableTab implements SearchableConfigurable, Co
public String getHelpTopic() {
return "reference.compiler.kotlin";
}
public JPanel getContentPane() {
return contentPane;
}
}
@@ -46,6 +46,17 @@ class KotlinFacetConfiguration : FacetConfiguration {
else {
settings = KotlinFacetSettings()
}
if (settings.useProjectSettings) {
with(settings.versionInfo) {
languageLevel = null
apiLevel = null
}
with(settings.compilerInfo) {
commonCompilerArguments = null
k2jsCompilerArguments = null
compilerSettings = null
}
}
}
@Suppress("OverridingDeprecatedMember")
@@ -20,9 +20,11 @@ import com.intellij.facet.impl.ui.libraries.DelegatingLibrariesValidatorContext
import com.intellij.facet.ui.*
import com.intellij.facet.ui.libraries.FrameworkLibraryValidator
import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.TargetPlatformKind
import java.awt.BorderLayout
import javax.swing.JCheckBox
import javax.swing.JComboBox
import javax.swing.JComponent
import javax.swing.JPanel
@@ -46,6 +48,8 @@ class KotlinFacetEditorGeneralTab(
}
}
private val useProjectSettingsCheckBox = JCheckBox("Use project settings")
private val languageVersionComboBox =
JComboBox<LanguageVersion>(LanguageVersion.values()).apply {
setRenderer(DescriptionListCellRenderer())
@@ -74,6 +78,10 @@ class KotlinFacetEditorGeneralTab(
validatorsManager.registerValidator(libraryValidator)
validatorsManager.registerValidator(versionValidator)
useProjectSettingsCheckBox.addActionListener {
useProjectSettingsChanged()
}
languageVersionComboBox.addActionListener {
validatorsManager.validate()
}
@@ -92,12 +100,25 @@ class KotlinFacetEditorGeneralTab(
reset()
}
private fun useProjectSettingsChanged() {
val useModuleSpecific = !useProjectSettingsCheckBox.isSelected
languageVersionComboBox.isEnabled = useModuleSpecific
apiVersionComboBox.isEnabled = useModuleSpecific
updateCompilerTab()
}
private fun updateCompilerTab() {
compilerTab.compilerConfigurable.setTargetPlatform(chosenPlatform)
UIUtil.setEnabled(compilerTab.compilerConfigurable.contentPane, !useProjectSettingsCheckBox.isSelected, true)
}
override fun isModified(): Boolean {
if (useProjectSettingsCheckBox.isSelected != configuration.settings.useProjectSettings) return true
return with(configuration.settings.versionInfo) {
if (useProjectSettingsCheckBox.isSelected) return targetPlatformComboBox.selectedItem != targetPlatformKind
languageVersionComboBox.selectedItem != languageLevel
|| targetPlatformComboBox.selectedItem != targetPlatformKind
|| apiVersionComboBox.selectedItem != apiLevel
@@ -105,18 +126,23 @@ class KotlinFacetEditorGeneralTab(
}
override fun reset() {
useProjectSettingsCheckBox.isSelected = configuration.settings.useProjectSettings
with(configuration.settings.versionInfo) {
languageVersionComboBox.selectedItem = languageLevel
targetPlatformComboBox.selectedItem = targetPlatformKind
apiVersionComboBox.selectedItem = apiLevel
targetPlatformComboBox.selectedItem = targetPlatformKind
}
useProjectSettingsChanged()
}
override fun apply() {
configuration.settings.useProjectSettings = useProjectSettingsCheckBox.isSelected
with(configuration.settings.versionInfo) {
languageLevel = languageVersionComboBox.selectedItem as LanguageVersion?
if (!useProjectSettingsCheckBox.isSelected) {
languageLevel = languageVersionComboBox.selectedItem as LanguageVersion?
apiLevel = apiVersionComboBox.selectedItem as LanguageVersion?
}
targetPlatformKind = targetPlatformComboBox.selectedItem as TargetPlatformKind<*>?
apiLevel = apiVersionComboBox.selectedItem as LanguageVersion?
}
}
@@ -126,6 +152,7 @@ class KotlinFacetEditorGeneralTab(
val mainPanel = JPanel(BorderLayout())
val contentPanel = FormBuilder
.createFormBuilder()
.addComponent(useProjectSettingsCheckBox)
.addLabeledComponent("&Language version: ", languageVersionComboBox)
.addLabeledComponent("&Standard library API version: ", apiVersionComboBox)
.addLabeledComponent("&Target platform: ", targetPlatformComboBox)
@@ -98,23 +98,31 @@ internal fun getLibraryLanguageLevel(
fun KotlinFacetSettings.initializeIfNeeded(module: Module, rootModel: ModuleRootModel?) {
val project = module.project
val commonArguments = KotlinCommonCompilerArgumentsHolder.getInstance(module.project).settings
with(versionInfo) {
if (targetPlatformKind == null) {
targetPlatformKind = getDefaultTargetPlatform(module, rootModel)
}
if (languageLevel == null) {
languageLevel = getDefaultLanguageLevel(module)
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
?: getDefaultLanguageLevel(module)
}
if (apiLevel == null) {
apiLevel = languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind!!))
apiLevel = if (useProjectSettings) {
LanguageVersion.fromVersionString(commonArguments.apiVersion) ?: languageLevel
}
else {
languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind!!))
}
}
}
with(compilerInfo) {
if (commonCompilerArguments == null) {
commonCompilerArguments = copyBean(KotlinCommonCompilerArgumentsHolder.getInstance(project).settings)
commonCompilerArguments = copyBean(commonArguments)
}
if (compilerSettings == null) {
@@ -141,6 +149,7 @@ fun Module.getOrCreateFacet(modelsProvider: IdeModifiableModelsProvider): Kotlin
val facet = with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) }
facetModel.addFacet(facet)
facet.configuration.settings.useProjectSettings = true
return facet
}
@@ -64,6 +64,7 @@ class JpsKotlinCompilerSettings : JpsElementBase<JpsKotlinCompilerSettings>() {
fun getCommonCompilerArguments(module: JpsModule): CommonCompilerArguments {
val defaultArguments = getSettings(module.project).commonCompilerArguments
val facetSettings = module.kotlinFacetExtension?.settings ?: return defaultArguments
if (facetSettings.useProjectSettings) return defaultArguments
val (languageLevel, apiLevel) = facetSettings.versionInfo
return facetSettings.compilerInfo.commonCompilerArguments?.apply {
languageVersion = languageLevel?.description
@@ -78,6 +79,7 @@ class JpsKotlinCompilerSettings : JpsElementBase<JpsKotlinCompilerSettings>() {
fun getK2JvmCompilerArguments(module: JpsModule): K2JVMCompilerArguments {
val defaultArguments = getSettings(module.project).k2JvmCompilerArguments
val facetSettings = module.kotlinFacetExtension?.settings ?: return defaultArguments
if (facetSettings.useProjectSettings) return defaultArguments
val targetPlatform = facetSettings.versionInfo.targetPlatformKind as? TargetPlatformKind.Jvm ?: return defaultArguments
return copyBean(defaultArguments).apply {
jvmTarget = targetPlatform.version.description
@@ -89,8 +91,10 @@ class JpsKotlinCompilerSettings : JpsElementBase<JpsKotlinCompilerSettings>() {
}
fun getK2JsCompilerArguments(module: JpsModule): K2JSCompilerArguments {
return module.kotlinFacetExtension?.settings?.compilerInfo?.k2jsCompilerArguments
?: getSettings(module.project).k2JsCompilerArguments
val defaultArguments = getSettings(module.project).k2JsCompilerArguments
val facetSettings = module.kotlinFacetExtension?.settings ?: return defaultArguments
if (facetSettings.useProjectSettings) return defaultArguments
return facetSettings.compilerInfo.k2jsCompilerArguments ?: defaultArguments
}
fun setK2JsCompilerArguments(project: JpsProject, k2JsCompilerArguments: K2JSCompilerArguments) {
@@ -98,7 +102,10 @@ class JpsKotlinCompilerSettings : JpsElementBase<JpsKotlinCompilerSettings>() {
}
fun getCompilerSettings(module: JpsModule): CompilerSettings {
return module.kotlinFacetExtension?.settings?.compilerInfo?.compilerSettings ?: getSettings(module.project).compilerSettings
val defaultSettings = getSettings(module.project).compilerSettings
val facetSettings = module.kotlinFacetExtension?.settings ?: return defaultSettings
if (facetSettings.useProjectSettings) return defaultSettings
return facetSettings.compilerInfo.compilerSettings ?: defaultSettings
}
fun setCompilerSettings(project: JpsProject, compilerSettings: CompilerSettings) {