diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinIcons.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinIcons.java index ed6adf6b15c..bedca62e090 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinIcons.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinIcons.java @@ -56,6 +56,7 @@ public interface KotlinIcons { Icon EXPECT = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/expect.svg"); Icon LAUNCH = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_launch_configuration.svg"); + Icon LOAD_SCRIPT_CONFIGURATION = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration.svg"); Icon JS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_js.svg"); Icon MPP = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_multiplatform_project.svg"); diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationNotificationFactory.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationNotificationFactory.kt index fbf36e946b0..ca57b194fb1 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationNotificationFactory.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationNotificationFactory.kt @@ -58,9 +58,8 @@ class DefaultScriptConfigurationNotificationFactory : ScriptConfigurationNotific withSelectedEditor(project) { manager -> val existingPanel = notificationPanel if (existingPanel != null) { - notificationPanel?.let { - manager.removeTopComponent(this, it) - } + existingPanel.onClick = onClick + return@withSelectedEditor } val panel = NewLoadConfigurationNotificationPanel(onClick, project) @@ -84,7 +83,7 @@ class DefaultScriptConfigurationNotificationFactory : ScriptConfigurationNotific by UserDataProperty(Key.create("load.script.configuration.panel")) private class NewLoadConfigurationNotificationPanel( - val onClick: () -> Unit, + var onClick: () -> Unit, project: Project ) : EditorNotificationPanel() { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/DefaultScriptConfigurationManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/DefaultScriptConfigurationManager.kt index 2120ad1a248..0a514ec618f 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/DefaultScriptConfigurationManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/DefaultScriptConfigurationManager.kt @@ -191,17 +191,16 @@ internal class DefaultScriptConfigurationManager(project: Project) : if (postponeLoading) { ScriptConfigurationNotificationFactory.NOTIFICATION_FACTORY.getPoint(project).extensionList.firstOrNull { it.showNotification(virtualFile, project) { - runAsyncLoaders(file, virtualFile, scriptDefinition, async, postponeLoading) + runAsyncLoaders(file, virtualFile, scriptDefinition, async, isLoadingPostponed = true) } } } else { - runAsyncLoaders(file, virtualFile, scriptDefinition, async, postponeLoading) + runAsyncLoaders(file, virtualFile, scriptDefinition, async, isLoadingPostponed = false) } } } } - // в нотификации остается старый колбек - нужно перезаписывать колбек private fun runAsyncLoaders( file: KtFile, virtualFile: VirtualFile, diff --git a/idea/idea-gradle/res/messages/KotlinIdeaGradleBundle.properties b/idea/idea-gradle/res/messages/KotlinIdeaGradleBundle.properties index 32cb8b42e3d..f6f2a0d0b05 100644 --- a/idea/idea-gradle/res/messages/KotlinIdeaGradleBundle.properties +++ b/idea/idea-gradle/res/messages/KotlinIdeaGradleBundle.properties @@ -53,3 +53,5 @@ notification.title.script.configuration.has.been.changed=Script configurations h notification.text.script.configuration.has.been.changed=Gradle Project needs to be imported to load changes. action.label.import.project=Import Project action.label.enable.auto.import=Enable Auto-Import +action.text.load.script.configurations=Load Script Configurations +action.description.load.script.configurations=Gradle Kotlin DSL script configuration has been changed. Load changes to get script code insight without loading the external Gradle project. diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt index 8f260be0f94..3e8057d5280 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt @@ -7,10 +7,17 @@ package org.jetbrains.kotlin.idea.scripting.gradle +import com.intellij.notification.* +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.externalSystem.util.ExternalSystemUtil import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import org.jetbrains.kotlin.idea.KotlinIcons +import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle +import org.jetbrains.kotlin.psi.UserDataProperty import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.util.GradleConstants @@ -25,4 +32,77 @@ fun runPartialGradleImport(project: Project) { ImportSpecBuilder(project, GradleConstants.SYSTEM_ID) .build() ) +} + +private val kotlinDslNotificationGroupId = "Gradle Kotlin DSL Scripts" +private var Project.notificationPanel: ScriptConfigurationChangedNotification? + by UserDataProperty(Key.create("load.script.configuration.panel")) + + +fun showNotificationForProjectImport(project: Project, callback: () -> Unit) { + val existingPanel = project.notificationPanel + if (existingPanel != null) { + existingPanel.update(callback) + return + } + + val notificationGroup = NotificationGroup.findRegisteredGroup(kotlinDslNotificationGroupId) + if (notificationGroup == null) { + NotificationsConfiguration.getNotificationsConfiguration().register( + kotlinDslNotificationGroupId, NotificationDisplayType.STICKY_BALLOON, false + ) + } + + val notification = ScriptConfigurationChangedNotification(project, callback) + project.notificationPanel = notification + notification.notify(project) +} + +fun hideNotificationForProjectImport(project: Project): Boolean { + if (project.notificationPanel == null) return false + project.notificationPanel?.expire() + return true +} + +private class ScriptConfigurationChangedNotification(val project: Project, onClick: () -> Unit) : + Notification( + kotlinDslNotificationGroupId, + KotlinIcons.LOAD_SCRIPT_CONFIGURATION, + KotlinIdeaGradleBundle.message("notification.title.script.configuration.has.been.changed"), + null, + KotlinIdeaGradleBundle.message("notification.text.script.configuration.has.been.changed"), + NotificationType.INFORMATION, + null + ) { + + init { + //NotificationGroup.findRegisteredGroup(s) ?: NotificationGroup.balloonGroup(s) + + addAction(LoadConfigurationAction(onClick)) + addAction(NotificationAction.createSimple(KotlinIdeaGradleBundle.message("action.label.enable.auto.import")) { + val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) + val projectSettings = gradleSettings.getLinkedProjectsSettings() + .filterIsInstance() + .firstOrNull() + if (projectSettings != null) { + projectSettings.isUseAutoImport = true + } + }) + } + + fun update(onClick: () -> Unit) { + actions.filterIsInstance().forEach { it.onClick = onClick } + } + + override fun expire() { + super.expire() + + project.notificationPanel = null + } + + private class LoadConfigurationAction(var onClick: () -> Unit) : AnAction(KotlinIdeaGradleBundle.message("action.label.import.project")) { + override fun actionPerformed(e: AnActionEvent) { + onClick() + } + } } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 index f3392a3cb21..a51bdfe7140 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt.201 @@ -7,13 +7,29 @@ package org.jetbrains.kotlin.idea.scripting.gradle +import com.intellij.diff.util.DiffUtil +import com.intellij.openapi.actionSystem.ActionManager +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.editor.Editor import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.externalSystem.util.ExternalSystemUtil +import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.testFramework.LightVirtualFileBase +import org.jetbrains.kotlin.idea.KotlinIcons +import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver -import org.jetbrains.plugins.gradle.service.project.GradleIncrementalResolverPolicy +import org.jetbrains.kotlin.psi.UserDataProperty +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition +import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy +import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.util.GradleConstants +import java.util.function.Predicate fun runPartialGradleImport(project: Project) { val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) @@ -25,9 +41,62 @@ fun runPartialGradleImport(project: Project) { projectSettings.externalProjectPath, ImportSpecBuilder(project, GradleConstants.SYSTEM_ID) .projectResolverPolicy( - GradleIncrementalResolverPolicy { - it is KotlinDslScriptModelResolver - } + GradlePartialResolverPolicy(Predicate { it is KotlinDslScriptModelResolver }) ) ) +} + +private var Project.notificationPanel: Boolean? + by UserDataProperty(Key.create("load.script.configuration.panel")) + + +fun showNotificationForProjectImport(project: Project, callback: () -> Unit) { + project.notificationPanel = true + (ActionManager.getInstance().getAction("LoadConfigurationAction") as LoadConfigurationAction).onClick = callback +} + +fun hideNotificationForProjectImport(project: Project): Boolean { + project.notificationPanel = false + return true +} + +class LoadConfigurationAction : AnAction( + KotlinIdeaGradleBundle.message("action.text.load.script.configurations"), + KotlinIdeaGradleBundle.message("action.description.load.script.configurations"), + KotlinIcons.LOAD_SCRIPT_CONFIGURATION +) { + + var onClick = {} + + override fun actionPerformed(e: AnActionEvent) { + onClick() + } + + override fun update(e: AnActionEvent) { + ensureValidActionVisibility(e) + + e.presentation.description = KotlinIdeaGradleBundle.message("action.description.load.script.configurations") + } + + private fun ensureValidActionVisibility(e: AnActionEvent) { + if (e.project?.notificationPanel != true) { + e.presentation.isVisible = false + return + } + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + when { + DiffUtil.isDiffEditor(editor) -> e.presentation.isVisible = false + !editor.isScriptEditor() -> e.presentation.isVisible = false + } + } + + private fun Editor.isScriptEditor(): Boolean { + val documentManager = FileDocumentManager.getInstance() + val virtualFile = documentManager.getFile(document) + if (virtualFile is LightVirtualFileBase) return false + if (virtualFile == null || !virtualFile.isValid) return false + + val project = project ?: return false + return virtualFile.findScriptDefinition(project) != null + } } \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationNotificationFactory.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationNotificationFactory.kt new file mode 100644 index 00000000000..12341d68a42 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptConfigurationNotificationFactory.kt @@ -0,0 +1,32 @@ +/* + * 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.scripting.gradle + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationNotificationFactory + +class GradleScriptConfigurationNotificationFactory : ScriptConfigurationNotificationFactory { + override fun showNotification(file: VirtualFile, project: Project, onClick: () -> Unit): Boolean { + if (isGradleKotlinScript(file) && isGradleImportCanBeUsed(project)) { + showNotificationForProjectImport(project, onClick) + return true + } + return false + } + + override fun hideNotification(file: VirtualFile, project: Project): Boolean { + return hideNotificationForProjectImport(project) + } + + private fun isGradleImportCanBeUsed(project: Project): Boolean { + val gradleVersion = getGradleVersion(project) + if (gradleVersion != null && kotlinDslScriptsModelImportSupported(gradleVersion)) { + return true + } + return false + } +} \ No newline at end of file diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index ec9c0ce20bd..7151437ef44 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -15,6 +15,9 @@ + diff --git a/idea/resources/META-INF/gradle.xml.201 b/idea/resources/META-INF/gradle.xml.201 index 5fabc060799..7be649b16cc 100644 --- a/idea/resources/META-INF/gradle.xml.201 +++ b/idea/resources/META-INF/gradle.xml.201 @@ -15,6 +15,9 @@ + @@ -29,7 +32,6 @@ - + + + + diff --git a/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration.svg b/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration.svg new file mode 100644 index 00000000000..16b4c6e08a6 --- /dev/null +++ b/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration_dark.svg b/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration_dark.svg new file mode 100644 index 00000000000..45ee07515e2 --- /dev/null +++ b/idea/resources/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration_dark.svg @@ -0,0 +1,5 @@ + + + + +