Kotlin Facet: Initial implementation

This commit is contained in:
Alexey Sedunov
2016-10-05 16:28:16 +03:00
parent 5c2ad48375
commit c6c65b1a20
8 changed files with 412 additions and 0 deletions
+1
View File
@@ -207,6 +207,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-12398`](https://youtrack.jetbrains.com/issue/KT-12398) Call Hierarchy: Show Kotlin usages of Java methods
- [`KT-13976`](https://youtrack.jetbrains.com/issue/KT-13976) Search Everywhere: Render function parameter types
- [`KT-13977`](https://youtrack.jetbrains.com/issue/KT-13977) Search Everywhere: Render extension type in prefix position
- Implement Kotlin facet
#### Intention actions, inspections and quickfixes
+2
View File
@@ -731,6 +731,8 @@
<usageToPsiElementProvider implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinUsageToPsiElementProvider"/>
<facetType implementation="org.jetbrains.kotlin.idea.facet.KotlinFacetType"/>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
<category>Kotlin</category>
@@ -0,0 +1,72 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.impl.ui.libraries.LibrariesValidatorContext
import com.intellij.facet.ui.FacetConfigurationQuickFix
import com.intellij.facet.ui.FacetValidatorsManager
import com.intellij.facet.ui.ValidationResult
import com.intellij.facet.ui.libraries.FrameworkLibraryValidator
import com.intellij.ide.IdeBundle
import com.intellij.openapi.roots.ui.configuration.libraries.AddCustomLibraryDialog
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
import com.intellij.openapi.roots.ui.configuration.libraries.LibraryPresentationManager
import javax.swing.JComponent
// Based on com.intellij.facet.impl.ui.libraries.FrameworkLibraryValidatorImpl
class FrameworkLibraryValidatorWithDynamicDescription(
private val context: LibrariesValidatorContext,
private val validatorsManager: FacetValidatorsManager,
private val libraryCategoryName: String,
private val getLibraryDescription: () -> CustomLibraryDescription
) : FrameworkLibraryValidator() {
override fun check(): ValidationResult {
val libraryDescription = getLibraryDescription()
val libraryKinds = libraryDescription.suitableLibraryKinds
var found = false
val presentationManager = LibraryPresentationManager.getInstance()
context.rootModel
.orderEntries()
.using(context.modulesProvider)
.recursively()
.librariesOnly()
.forEachLibrary { library ->
if (presentationManager.isLibraryOfKind(library, context.librariesContainer, libraryKinds)) {
found = true
}
!found
}
if (found) return ValidationResult.OK
return ValidationResult(
IdeBundle.message("label.missed.libraries.text", libraryCategoryName),
LibrariesQuickFix(libraryDescription)
)
}
private inner class LibrariesQuickFix(
private val myDescription: CustomLibraryDescription
) : FacetConfigurationQuickFix(IdeBundle.message("button.fix")) {
override fun run(place: JComponent) {
val dialog = AddCustomLibraryDialog.createDialog(myDescription, context.librariesContainer,
context.module, context.modifiableRootModel,
null)
dialog.show()
validatorsManager.validate()
}
}
}
@@ -0,0 +1,34 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.Facet
import com.intellij.facet.FacetManager.getInstance
import com.intellij.openapi.module.Module
class KotlinFacet(
module: Module,
name: String,
configuration: KotlinFacetConfiguration
) : Facet<KotlinFacetConfiguration>(KotlinFacetType.INSTANCE, module, name, configuration, null) {
companion object {
fun get(module: Module): KotlinFacet? {
if (module.isDisposed) return null
return getInstance(module).getFacetByType<KotlinFacet>(KotlinFacetType.TYPE_ID)
}
}
}
@@ -0,0 +1,66 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.FacetConfiguration
import com.intellij.facet.ui.FacetEditorContext
import com.intellij.facet.ui.FacetEditorTab
import com.intellij.facet.ui.FacetValidatorsManager
import com.intellij.openapi.components.PersistentStateComponent
import org.jdom.Element
import org.jetbrains.kotlin.idea.util.DescriptionAware
class KotlinFacetConfiguration : FacetConfiguration, PersistentStateComponent<KotlinFacetConfiguration.Settings> {
enum class LanguageLevel(override val description: String) : DescriptionAware {
KOTLIN_1_0("1.0"),
KOTLIN_1_1("1.1")
}
enum class TargetPlatform(override val description: String) : DescriptionAware {
JVM_1_6("JVM 1.6"),
JVM_1_8("JVM 1.8"),
JS("JavaScript")
}
class Settings {
var languageLevel: LanguageLevel? = null
var targetPlatformKind: TargetPlatform? = null
}
private var settings = Settings()
@Suppress("OverridingDeprecatedMember")
override fun readExternal(element: Element?) {
}
@Suppress("OverridingDeprecatedMember")
override fun writeExternal(element: Element?) {
}
override fun loadState(state: Settings) {
this.settings = settings
}
override fun getState() = settings
override fun createEditorTabs(
editorContext: FacetEditorContext,
validatorsManager: FacetValidatorsManager
): Array<FacetEditorTab> = arrayOf(KotlinFacetEditorTab(this, editorContext, validatorsManager))
}
@@ -0,0 +1,165 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.impl.ui.libraries.DelegatingLibrariesValidatorContext
import com.intellij.facet.ui.FacetEditorContext
import com.intellij.facet.ui.FacetEditorTab
import com.intellij.facet.ui.FacetValidatorsManager
import com.intellij.facet.ui.libraries.FrameworkLibraryValidator
import com.intellij.framework.library.LibraryVersionProperties
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.JavaSdkVersion
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
import com.intellij.util.ui.FormBuilder
import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
import org.jetbrains.kotlin.idea.framework.getLibraryProperties
import org.jetbrains.kotlin.idea.util.DescriptionAware
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
import java.awt.BorderLayout
import java.awt.Component
import javax.swing.*
class KotlinFacetEditorTab(
private val configuration: KotlinFacetConfiguration,
private val editorContext: FacetEditorContext,
validatorsManager: FacetValidatorsManager
) : FacetEditorTab() {
class DescriptionListCellRenderer : DefaultListCellRenderer() {
override fun getListCellRendererComponent(list: JList<*>?, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean): Component {
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus).apply {
text = (value as? DescriptionAware)?.description ?: ""
}
}
}
private val KotlinFacetConfiguration.TargetPlatform.libraryDescription: CustomLibraryDescription
get() {
return when (this) {
KotlinFacetConfiguration.TargetPlatform.JVM_1_6, KotlinFacetConfiguration.TargetPlatform.JVM_1_8 ->
JavaRuntimeLibraryDescription(editorContext.project)
KotlinFacetConfiguration.TargetPlatform.JS ->
JSLibraryStdDescription(editorContext.project)
}
}
private val languageVersionComboBox =
JComboBox<KotlinFacetConfiguration.LanguageLevel>(KotlinFacetConfiguration.LanguageLevel.values()).apply {
setRenderer(DescriptionListCellRenderer())
}
private val targetPlatformComboBox =
JComboBox<KotlinFacetConfiguration.TargetPlatform>(KotlinFacetConfiguration.TargetPlatform.values()).apply {
setRenderer(DescriptionListCellRenderer())
}
private val validator: FrameworkLibraryValidator
private fun getRuntimeLibraryVersions(
libToProperties: Library.() -> LibraryVersionProperties?
): List<String> {
return editorContext
.rootModel
.orderEntries
.asSequence()
.filterIsInstance<LibraryOrderEntry>()
.mapNotNull { it.library?.libToProperties()?.versionString }
.toList()
}
private fun getDefaultTargetPlatform(): KotlinFacetConfiguration.TargetPlatform {
getRuntimeLibraryVersions { getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), this) }.firstOrNull()?.let { javaLib ->
return KotlinFacetConfiguration.TargetPlatform.JS
}
val sdk = editorContext.rootModel.sdk
val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!)
return when {
sdkVersion != null && sdkVersion <= JavaSdkVersion.JDK_1_6 -> KotlinFacetConfiguration.TargetPlatform.JVM_1_6
else -> KotlinFacetConfiguration.TargetPlatform.JVM_1_8
}
}
private fun getDefaultLanguageLevel(): KotlinFacetConfiguration.LanguageLevel {
val libVersion = bundledRuntimeVersion()
return when {
libVersion.startsWith("1.0") -> KotlinFacetConfiguration.LanguageLevel.KOTLIN_1_0
else -> KotlinFacetConfiguration.LanguageLevel.KOTLIN_1_1
}
}
init {
validator = FrameworkLibraryValidatorWithDynamicDescription(
DelegatingLibrariesValidatorContext(editorContext),
validatorsManager,
"kotlin"
) { (targetPlatformComboBox.selectedItem as KotlinFacetConfiguration.TargetPlatform).libraryDescription }
validatorsManager.registerValidator(validator)
targetPlatformComboBox.addActionListener {
validatorsManager.validate()
}
with(configuration.state) {
if (targetPlatformKind == null) {
targetPlatformKind = getDefaultTargetPlatform()
}
if (languageLevel == null) {
languageLevel = getDefaultLanguageLevel()
}
}
reset()
}
override fun isModified(): Boolean {
return languageVersionComboBox.selectedItem != configuration.state.languageLevel
|| targetPlatformComboBox.selectedItem != configuration.state.targetPlatformKind
}
override fun reset() {
languageVersionComboBox.selectedItem = configuration.state.languageLevel
targetPlatformComboBox.selectedItem = configuration.state.targetPlatformKind
}
override fun apply() {
configuration.state.languageLevel = languageVersionComboBox.selectedItem as KotlinFacetConfiguration.LanguageLevel?
configuration.state.targetPlatformKind = targetPlatformComboBox.selectedItem as KotlinFacetConfiguration.TargetPlatform?
}
override fun getDisplayName() = "Kotlin"
override fun createComponent(): JComponent {
val mainPanel = JPanel(BorderLayout())
val contentPanel = FormBuilder
.createFormBuilder()
.addLabeledComponent("&Language version: ", languageVersionComboBox)
.addLabeledComponent("&Target platform: ", targetPlatformComboBox)
.panel
mainPanel.add(contentPanel, BorderLayout.NORTH)
return mainPanel
}
override fun disposeUIResources() {
}
}
@@ -0,0 +1,51 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.Facet
import com.intellij.facet.FacetType
import com.intellij.facet.FacetTypeId
import com.intellij.facet.FacetTypeRegistry
import com.intellij.openapi.module.JavaModuleType
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleType
import org.jetbrains.kotlin.idea.KotlinIcons
import javax.swing.Icon
class KotlinFacetType : FacetType<KotlinFacet, KotlinFacetConfiguration>(TYPE_ID, ID, NAME) {
companion object {
val TYPE_ID = FacetTypeId<KotlinFacet>("kotlin-language")
val ID = "kotlin-language"
val NAME = "Kotlin"
val INSTANCE: KotlinFacetType
get() = FacetTypeRegistry.getInstance().findFacetType(TYPE_ID) as KotlinFacetType
}
override fun isSuitableModuleType(moduleType: ModuleType<*>) = moduleType is JavaModuleType
override fun getIcon(): Icon = KotlinIcons.SMALL_LOGO
override fun createDefaultConfiguration() = KotlinFacetConfiguration()
override fun createFacet(
module: Module,
name: String,
configuration: KotlinFacetConfiguration,
underlyingFacet: Facet<*>?
) = KotlinFacet(module, name, configuration)
}
@@ -0,0 +1,21 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.util
interface DescriptionAware {
val description: String
}