diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 3fdd12e8d0d..76cd6b1c581 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -666,6 +666,8 @@ + + org.jetbrains.kotlin.idea.intentions.IfNullToElvisIntention Kotlin diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinCreateFromTemplateHandler.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinCreateFromTemplateHandler.kt new file mode 100644 index 00000000000..e2acfe83381 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinCreateFromTemplateHandler.kt @@ -0,0 +1,41 @@ +/* + * 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.actions + +import com.intellij.ide.fileTemplates.DefaultCreateFromTemplateHandler +import com.intellij.ide.fileTemplates.FileTemplate +import org.jetbrains.kotlin.idea.KotlinFileType +import org.jetbrains.kotlin.idea.core.quoteIfNeeded + +class KotlinCreateFromTemplateHandler : DefaultCreateFromTemplateHandler() { + override fun handlesTemplate(template: FileTemplate) = template.isTemplateOfType(KotlinFileType.INSTANCE) + + override fun prepareProperties(props: MutableMap) { + val packageName = props[FileTemplate.ATTRIBUTE_PACKAGE_NAME] as? String + if (packageName != null) { + props[FileTemplate.ATTRIBUTE_PACKAGE_NAME] = packageName + .split('.') + .map { it.quoteIfNeeded() } + .joinToString(".") + } + + val name = props[FileTemplate.ATTRIBUTE_NAME] as? String + if (name != null) { + props[FileTemplate.ATTRIBUTE_NAME] = name.quoteIfNeeded() + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/NewKotlinFileAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/NewKotlinFileAction.kt index a7f2a5816e5..039a30fd9bd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/NewKotlinFileAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/NewKotlinFileAction.kt @@ -18,18 +18,25 @@ package org.jetbrains.kotlin.idea.actions import com.intellij.ide.actions.CreateFileFromTemplateAction import com.intellij.ide.actions.CreateFileFromTemplateDialog +import com.intellij.ide.fileTemplates.FileTemplate +import com.intellij.ide.fileTemplates.FileTemplateManager +import com.intellij.ide.fileTemplates.actions.AttributesDefaults +import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.LangDataKeys import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectRootManager import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiFile +import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.configuration.showConfigureKotlinNotificationIfNeeded +import java.util.* class NewKotlinFileAction : CreateFileFromTemplateAction("Kotlin File/Class", @@ -74,4 +81,59 @@ class NewKotlinFileAction override fun equals(obj: Any?): Boolean { return obj is NewKotlinFileAction } + + override fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? { + val directorySeparators = if (template.name == "Kotlin File") arrayOf('/', '\\') else arrayOf('/', '\\', '.') + val (className, targetDir) = findOrCreateTarget(dir, name, directorySeparators) + + val service = DumbService.getInstance(dir.project) + service.isAlternativeResolveEnabled = true + try { + return createFromTemplate(targetDir, className, template) + } + finally { + service.isAlternativeResolveEnabled = false + } + } + + private fun findOrCreateTarget(dir: PsiDirectory, name: String, directorySeparators: Array): Pair { + var className = name.removeSuffix(".kt") + var targetDir = dir + + for (splitChar in directorySeparators) { + if (splitChar in className) { + val names = className.trim().split(splitChar) + + for (dirName in names.dropLast(1)) { + targetDir = targetDir.findSubdirectory(dirName) ?: targetDir.createSubdirectory(dirName) + } + + className = names.last() + break + } + } + return Pair(className, targetDir) + } + + private fun createFromTemplate(dir: PsiDirectory, className: String, template: FileTemplate): PsiFile? { + val project = dir.project + val defaultProperties = FileTemplateManager.getInstance(project).defaultProperties + + val properties = Properties(defaultProperties) + + val element = try { + CreateFromTemplateDialog(project, dir, template, + AttributesDefaults(className).withFixedName(true), + properties).create() + } + catch (e: IncorrectOperationException) { + throw e + } + catch (e: Exception) { + LOG.error(e) + return null + } + + return element.containingFile + } }