diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/gradle.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/gradle.kt deleted file mode 100644 index b6fb5f2a5b8..00000000000 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/gradle.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2010-2019 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.core.script.configuration - -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.registry.Registry -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiRecursiveElementVisitor -import com.intellij.psi.PsiWhiteSpace -import com.intellij.psi.impl.source.tree.LeafPsiElement -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs -import org.jetbrains.kotlin.idea.core.script.configuration.listener.DefaultScriptChangeListener -import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater -import org.jetbrains.kotlin.idea.core.script.configuration.loader.DefaultScriptConfigurationLoader -import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext -import org.jetbrains.kotlin.idea.core.util.EDT -import org.jetbrains.kotlin.idea.util.application.runReadAction -import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.psi.KtCallExpression -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtScriptInitializer -import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType -import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition - -class GradleScriptListener : DefaultScriptChangeListener() { - private val listenGradleRelatedFiles = false // todo - - override fun editorActivated(file: KtFile, updater: ScriptConfigurationUpdater): Boolean { - if (!isGradleKotlinScript(file.virtualFile)) return false - if (listenGradleRelatedFiles) { - updater.ensureUpToDatedConfigurationSuggested(file) - // todo: force reload if related files changed - } else { - // configuration will be reloaded after editor activation, even it is already up-to-date - // this is required for Gradle scripts, since it's classpath may depend on other files (`.properties` for example) - updater.forceConfigurationReload(file) - } - - return true - } -} - -class GradleScriptConfigurationLoader(project: Project) : DefaultScriptConfigurationLoader(project) { - private val useProjectImport: Boolean - get() = Registry.`is`("kotlin.gradle.scripts.useIdeaProjectImport", false) - - override fun shouldRunInBackground(scriptDefinition: ScriptDefinition): Boolean { - return if (useProjectImport) false else super.shouldRunInBackground(scriptDefinition) - } - - override fun loadDependencies( - isFirstLoad: Boolean, - ktFile: KtFile, - scriptDefinition: ScriptDefinition, - context: ScriptConfigurationLoadingContext - ): Boolean { - if (!isGradleKotlinScript(ktFile.originalFile.virtualFile)) return false - - if (useProjectImport) { - // do nothing, project import notification will be already showed - // and configuration for gradle build scripts will be saved at the end of import - // todo: use default configuration loader for out-of-project scripts? - - return true - } else { - // Gradle read files from FS - GlobalScope.launch(EDT(project)) { - runWriteAction { - FileDocumentManager.getInstance().saveAllDocuments() - } - } - - return super.loadDependencies(isFirstLoad, ktFile, scriptDefinition, context) - } - } - - override fun getInputsStamp(virtualFile: VirtualFile, file: KtFile): CachedConfigurationInputs { - return getGradleScriptInputsStamp(project, virtualFile, file) ?: super.getInputsStamp(virtualFile, file) - } -} - -data class GradleKotlinScriptConfigurationInputs( - val buildScriptAndPluginsSections: String -) : CachedConfigurationInputs { - override fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile?): Boolean { - val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) - return actualStamp == this - } -} - -fun isGradleKotlinScript(virtualFile: VirtualFile) = virtualFile.name.endsWith(".gradle.kts") - -fun getGradleScriptInputsStamp( - project: Project, - file: VirtualFile, - givenKtFile: KtFile? = null -): GradleKotlinScriptConfigurationInputs? { - if (!isGradleKotlinScript(file)) return null - - return runReadAction { - val ktFile = givenKtFile ?: PsiManager.getInstance(project).findFile(file) as? KtFile - - if (ktFile != null) { - val result = StringBuilder() - ktFile.script?.blockExpression - ?.getChildrenOfType() - ?.forEach { - val call = it.children.singleOrNull() as? KtCallExpression - val callRef = call?.firstChild?.text - if (callRef == "buildscript" || callRef == "plugins") { - result.append(callRef) - val lambda = call.lambdaArguments.singleOrNull() - lambda?.accept(object : PsiRecursiveElementVisitor(false) { - override fun visitElement(element: PsiElement) { - super.visitElement(element) - when (element) { - is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n") - is LeafPsiElement -> result.append(element.text) - } - } - }) - result.append("\n") - } - } - - GradleKotlinScriptConfigurationInputs(result.toString()) - } else null - } -} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleBuildScriptsDataService.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleBuildScriptsDataService.kt index c68920cad90..9594a4507cc 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleBuildScriptsDataService.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleBuildScriptsDataService.kt @@ -25,7 +25,7 @@ import com.intellij.pom.Navigatable import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot -import org.jetbrains.kotlin.idea.core.script.configuration.getGradleScriptInputsStamp +import org.jetbrains.kotlin.idea.script.getGradleScriptInputsStamp import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt new file mode 100644 index 00000000000..a8f51fc25c9 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleKotlinScriptConfigurationInputs.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2019 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.script + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs +import org.jetbrains.kotlin.psi.KtFile + +data class GradleKotlinScriptConfigurationInputs( + val buildScriptAndPluginsSections: String +) : CachedConfigurationInputs { + override fun isUpToDate(project: Project, file: VirtualFile, ktFile: KtFile?): Boolean { + val actualStamp = getGradleScriptInputsStamp(project, file, ktFile) + return actualStamp == this + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationLoader.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationLoader.kt new file mode 100644 index 00000000000..78ff2fb214c --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationLoader.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2019 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.script + +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.vfs.VirtualFile +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs +import org.jetbrains.kotlin.idea.core.script.configuration.loader.DefaultScriptConfigurationLoader +import org.jetbrains.kotlin.idea.core.script.configuration.loader.ScriptConfigurationLoadingContext +import org.jetbrains.kotlin.idea.core.util.EDT +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition + +class GradleScriptConfigurationLoader(project: Project) : DefaultScriptConfigurationLoader(project) { + private val useProjectImport: Boolean + get() = Registry.`is`("kotlin.gradle.scripts.useIdeaProjectImport", false) + + override fun shouldRunInBackground(scriptDefinition: ScriptDefinition): Boolean { + return if (useProjectImport) false else super.shouldRunInBackground(scriptDefinition) + } + + override fun loadDependencies( + isFirstLoad: Boolean, + virtualFile: VirtualFile, + scriptDefinition: ScriptDefinition, + context: ScriptConfigurationLoadingContext + ): Boolean { + if (!isGradleKotlinScript(virtualFile)) return false + + if (useProjectImport) { + // do nothing, project import notification will be already showed + // and configuration for gradle build scripts will be saved at the end of import + // todo: use default configuration loader for out-of-project scripts? + + return true + } else { + // Gradle read files from FS + GlobalScope.launch(EDT(project)) { + runWriteAction { + FileDocumentManager.getInstance().saveAllDocuments() + } + } + + return super.loadDependencies(isFirstLoad, virtualFile, scriptDefinition, context) + } + } + + override fun getInputsStamp(virtualFile: VirtualFile, file: KtFile): CachedConfigurationInputs { + return getGradleScriptInputsStamp(project, virtualFile, file) + ?: super.getInputsStamp(virtualFile, file) + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt new file mode 100644 index 00000000000..0bd4cbe6578 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2019 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.script + +import org.jetbrains.kotlin.idea.core.script.configuration.listener.DefaultScriptChangeListener +import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater +import org.jetbrains.kotlin.psi.KtFile + +class GradleScriptListener : DefaultScriptChangeListener() { + private val listenGradleRelatedFiles = false // todo + + override fun editorActivated(file: KtFile, updater: ScriptConfigurationUpdater): Boolean { + if (!isGradleKotlinScript(file.virtualFile)) return false + if (listenGradleRelatedFiles) { + updater.ensureUpToDatedConfigurationSuggested(file) + // todo: force reload if related files changed + } else { + // configuration will be reloaded after editor activation, even it is already up-to-date + // this is required for Gradle scripts, since it's classpath may depend on other files (`.properties` for example) + updater.forceConfigurationReload(file) + } + + return true + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt new file mode 100644 index 00000000000..146753473b0 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/utils.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2019 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.script + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiRecursiveElementVisitor +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtScriptInitializer +import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType + +fun isGradleKotlinScript(virtualFile: VirtualFile) = virtualFile.name.endsWith(".gradle.kts") + +fun getGradleScriptInputsStamp( + project: Project, + file: VirtualFile, + givenKtFile: KtFile? = null +): GradleKotlinScriptConfigurationInputs? { + if (!isGradleKotlinScript(file)) return null + + return runReadAction { + val ktFile = givenKtFile ?: PsiManager.getInstance(project).findFile(file) as? KtFile + + if (ktFile != null) { + val result = StringBuilder() + ktFile.script?.blockExpression + ?.getChildrenOfType() + ?.forEach { + val call = it.children.singleOrNull() as? KtCallExpression + val callRef = call?.firstChild?.text + if (callRef == "buildscript" || callRef == "plugins") { + result.append(callRef) + val lambda = call.lambdaArguments.singleOrNull() + lambda?.accept(object : PsiRecursiveElementVisitor(false) { + override fun visitElement(element: PsiElement) { + super.visitElement(element) + when (element) { + is PsiWhiteSpace -> if (element.text.contains("\n")) result.append("\n") + is LeafPsiElement -> result.append(element.text) + } + } + }) + result.append("\n") + } + } + + GradleKotlinScriptConfigurationInputs(result.toString()) + } else null + } +} \ No newline at end of file diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index 483c7753d65..a4360c8c29d 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -12,6 +12,11 @@ + + + + + diff --git a/idea/resources/META-INF/gradle.xml.183 b/idea/resources/META-INF/gradle.xml.183 index 165e4c1970b..2416b27df72 100644 --- a/idea/resources/META-INF/gradle.xml.183 +++ b/idea/resources/META-INF/gradle.xml.183 @@ -12,6 +12,11 @@ + + + + +