diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptDiagnosticFixProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptDiagnosticFixProvider.kt new file mode 100644 index 00000000000..9fb090feff5 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptDiagnosticFixProvider.kt @@ -0,0 +1,21 @@ +/* + * 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. + */ + +@file:Suppress("PackageDirectoryMismatch") +// TODO: move to scripting-idea module +package org.jetbrains.kotlin.idea.script + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.extensions.ExtensionPointName +import kotlin.script.experimental.api.ScriptDiagnostic + +interface ScriptDiagnosticFixProvider { + + fun provideFixes(annotation: ScriptDiagnostic): List + + companion object { + val EP_NAME = ExtensionPointName.create("org.jetbrains.kotlin.scriptDiagnosticFixProvider") + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt index e6a239e66b5..60b72371a87 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt @@ -37,6 +37,7 @@ import com.intellij.openapi.wm.ex.StatusBarEx import com.intellij.psi.PsiFile import com.intellij.util.ui.UIUtil import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink +import org.jetbrains.kotlin.idea.script.ScriptDiagnosticFixProvider import org.jetbrains.kotlin.psi.KtFile import kotlin.script.experimental.api.ScriptDiagnostic import kotlin.script.experimental.api.SourceCode @@ -54,19 +55,25 @@ class ScriptExternalHighlightingPass( val reports = IdeScriptReportSink.getReports(file.virtualFile) - val annotations = reports.mapNotNull { (message, severity, _ , location) -> - val (startOffset, endOffset) = location?.let { computeOffsets(document, it) } ?: 0 to 0 + val annotations = reports.mapNotNull { scriptDiagnostic -> + val (startOffset, endOffset) = scriptDiagnostic.location?.let { computeOffsets(document, it) } ?: 0 to 0 val annotation = Annotation( startOffset, endOffset, - severity.convertSeverity() ?: return@mapNotNull null, - message, - message + scriptDiagnostic.severity.convertSeverity() ?: return@mapNotNull null, + scriptDiagnostic.message, + scriptDiagnostic.message ) // if range is empty, show notification panel in editor annotation.isFileLevelAnnotation = startOffset == endOffset + for (provider in ScriptDiagnosticFixProvider.EP_NAME.extensions) { + provider.provideFixes(scriptDiagnostic).forEach { + annotation.registerFix(it) + } + } + annotation } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt.182 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt.182 index 9f7057e22b0..c2fb2faa7aa 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt.182 +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt.182 @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater +import org.jetbrains.kotlin.idea.script.ScriptDiagnosticFixProvider import org.jetbrains.kotlin.psi.KtFile import kotlin.script.experimental.api.ScriptDiagnostic import kotlin.script.experimental.api.SourceCode @@ -75,19 +76,25 @@ class ScriptExternalHighlightingPass( val reports = IdeScriptReportSink.getReports(file.virtualFile) - val annotations = reports.mapNotNull { (message, severity, _ , location) -> - val (startOffset, endOffset) = location?.let { computeOffsets(document, it) } ?: 0 to 0 + val annotations = reports.mapNotNull { scriptDiagnostic -> + val (startOffset, endOffset) = scriptDiagnostic.location?.let { computeOffsets(document, it) } ?: 0 to 0 val annotation = Annotation( startOffset, endOffset, - severity.convertSeverity() ?: return@mapNotNull null, - message, - message + scriptDiagnostic.severity.convertSeverity() ?: return@mapNotNull null, + scriptDiagnostic.message, + scriptDiagnostic.message ) // if range is empty, show notification panel in editor annotation.isFileLevelAnnotation = startOffset == endOffset + for (provider in ScriptDiagnosticFixProvider.EP_NAME.extensions) { + provider.provideFixes(scriptDiagnostic).forEach { + annotation.registerFix(it) + } + } + annotation } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt new file mode 100644 index 00000000000..7b82cd43452 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/actions/ShowKotlinGradleDslLogs.kt @@ -0,0 +1,83 @@ +/* + * 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.actions + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.ide.actions.ShowFilePathAction +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.MessageType +import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.wm.WindowManager +import com.intellij.psi.PsiFile +import com.intellij.ui.BrowserHyperlinkListener +import java.io.File + +class ShowKotlinGradleDslLogs : IntentionAction, AnAction(), DumbAware { + override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { + openLogsDirIfPresent(project) + } + + override fun actionPerformed(e: AnActionEvent) { + openLogsDirIfPresent(e.project) + } + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = ShowFilePathAction.isSupported() + + override fun update(e: AnActionEvent) { + val presentation = e.presentation + presentation.isVisible = ShowFilePathAction.isSupported() + presentation.text = NAME + } + + private fun openLogsDirIfPresent(project: Project?) { + val logsDir = findLogsDir() + if (logsDir != null) { + ShowFilePathAction.openDirectory(logsDir) + } else { + val parent = WindowManager.getInstance().getStatusBar(project)?.component + ?: WindowManager.getInstance().findVisibleFrame().rootPane + JBPopupFactory.getInstance() + .createHtmlTextBalloonBuilder( + "Gradle DSL Logs cannot be found automatically.
See how to find logs here.", + MessageType.ERROR, + BrowserHyperlinkListener.INSTANCE + ) + .setFadeoutTime(5000) + .createBalloon() + .showInCenterOf(parent) + } + } + + /** The way how to find Gradle logs is described here + * @see org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs.gradleTroubleshootingLink + */ + private fun findLogsDir(): File? { + val userHome = System.getProperty("user.home") + return when { + SystemInfo.isMac -> File("$userHome/Library/Logs/gradle-kotlin-dsl") + SystemInfo.isLinux -> File("$userHome/.gradle-kotlin-dsl/logs") + SystemInfo.isWindows -> File("$userHome/AppData/Local/gradle-kotlin-dsl/log") + else -> null + }.takeIf { it?.exists() == true } + } + + override fun startInWriteAction() = false + + override fun getText() = NAME + + override fun getFamilyName() = NAME + + companion object { + private const val gradleTroubleshootingLink = "https://docs.gradle.org/current/userguide/kotlin_dsl.html#troubleshooting" + + val NAME = "Show Kotlin Gradle DSL Logs in ${ShowFilePathAction.getFileManagerName()}" + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/script/GradleScriptDiagnosticFixProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/script/GradleScriptDiagnosticFixProvider.kt new file mode 100644 index 00000000000..8ce42305c79 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/script/GradleScriptDiagnosticFixProvider.kt @@ -0,0 +1,25 @@ +/* + * 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.codeInsight.intention.IntentionAction +import org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs +import kotlin.script.experimental.api.ScriptDiagnostic + +class GradleScriptDiagnosticFixProvider : ScriptDiagnosticFixProvider { + override fun provideFixes(annotation: ScriptDiagnostic): List { + if (gradleMessagesForQuickFix.any { annotation.message.contains(it) }) { + return listOf(ShowKotlinGradleDslLogs()) + } + return emptyList() + } + + private val gradleMessagesForQuickFix = arrayListOf( + "This script caused build configuration to fail", + "see IDE logs for more information", + "Script dependencies resolution failed" + ) +} \ No newline at end of file diff --git a/idea/resources/META-INF/extensions/ide.xml b/idea/resources/META-INF/extensions/ide.xml index 1e6608cfc66..2a1b860c127 100644 --- a/idea/resources/META-INF/extensions/ide.xml +++ b/idea/resources/META-INF/extensions/ide.xml @@ -52,6 +52,9 @@ + + diff --git a/idea/resources/META-INF/extensions/ide.xml.183 b/idea/resources/META-INF/extensions/ide.xml.183 index a7130d04be9..709fcb85ad8 100644 --- a/idea/resources/META-INF/extensions/ide.xml.183 +++ b/idea/resources/META-INF/extensions/ide.xml.183 @@ -60,6 +60,9 @@ + + diff --git a/idea/resources/META-INF/extensions/ide.xml.as33 b/idea/resources/META-INF/extensions/ide.xml.as33 index 8b694b6c87f..692b205b38c 100644 --- a/idea/resources/META-INF/extensions/ide.xml.as33 +++ b/idea/resources/META-INF/extensions/ide.xml.as33 @@ -47,11 +47,14 @@ interface="org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension" area="IDEA_PROJECT"/> + + - + diff --git a/idea/resources/META-INF/extensions/ide.xml.as34 b/idea/resources/META-INF/extensions/ide.xml.as34 index 2ccd753bf9a..8becb0e1130 100644 --- a/idea/resources/META-INF/extensions/ide.xml.as34 +++ b/idea/resources/META-INF/extensions/ide.xml.as34 @@ -47,11 +47,14 @@ interface="org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension" area="IDEA_PROJECT"/> + + - + diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index a06b6441aa2..12fc24f1ab2 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -9,6 +9,7 @@ + @@ -22,4 +23,10 @@ + + + + + diff --git a/idea/resources/META-INF/gradle.xml.183 b/idea/resources/META-INF/gradle.xml.183 index 61f86b55ece..e7d22de87aa 100644 --- a/idea/resources/META-INF/gradle.xml.183 +++ b/idea/resources/META-INF/gradle.xml.183 @@ -9,6 +9,7 @@ + @@ -21,4 +22,10 @@ + + + + +