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 3ae4c5b4186..9d451fe08e2 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,9 +37,6 @@ 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.core.script.ScriptDefinitionsManager -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager -import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.psi.KtFile import kotlin.script.experimental.dependencies.ScriptReport @@ -54,24 +51,6 @@ class ScriptExternalHighlightingPass( if (!file.isScript()) return - if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) { - showNotification( - file, - "Highlighting in scripts is not available until all Script Definitions are loaded" - ) - } - - if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { - // initiate configuration refinement, if needed - ScriptDependenciesManager.getInstance(file.project).getRefinedCompilationConfiguration(file.virtualFile) - if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { - showNotification( - file, - "Highlighting in scripts is not available until all Script Dependencies are loaded" - ) - } - } - val reports = file.virtualFile.getUserData(IdeScriptReportSink.Reports) ?: return val annotations = reports.mapNotNull { (message, severity, position) -> 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 new file mode 100644 index 00000000000..3ae4c5b4186 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt.182 @@ -0,0 +1,158 @@ +/* + * Copyright 2010-2017 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.highlighter + +import com.intellij.codeHighlighting.Pass +import com.intellij.codeHighlighting.TextEditorHighlightingPass +import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory +import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar +import com.intellij.codeInsight.daemon.impl.HighlightInfo +import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.lang.annotation.HighlightSeverity.* +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.ProjectComponent +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.ui.MessageType +import com.intellij.openapi.wm.WindowManager +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.core.script.ScriptDefinitionsManager +import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater +import org.jetbrains.kotlin.psi.KtFile +import kotlin.script.experimental.dependencies.ScriptReport + +class ScriptExternalHighlightingPass( + private val file: KtFile, + document: Document +) : TextEditorHighlightingPass(file.project, document), DumbAware { + override fun doCollectInformation(progress: ProgressIndicator) = Unit + + override fun doApplyInformationToEditor() { + val document = document ?: return + + if (!file.isScript()) return + + if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) { + showNotification( + file, + "Highlighting in scripts is not available until all Script Definitions are loaded" + ) + } + + if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { + // initiate configuration refinement, if needed + ScriptDependenciesManager.getInstance(file.project).getRefinedCompilationConfiguration(file.virtualFile) + if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { + showNotification( + file, + "Highlighting in scripts is not available until all Script Dependencies are loaded" + ) + } + } + + val reports = file.virtualFile.getUserData(IdeScriptReportSink.Reports) ?: return + + val annotations = reports.mapNotNull { (message, severity, position) -> + val (startOffset, endOffset) = position?.let { computeOffsets(document, position) } ?: 0 to 0 + val annotation = Annotation( + startOffset, + endOffset, + severity.convertSeverity() ?: return@mapNotNull null, + message, + message + ) + + // if range is empty, show notification panel in editor + annotation.isFileLevelAnnotation = startOffset == endOffset + + annotation + } + + val infos = annotations.map { HighlightInfo.fromAnnotation(it) } + UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) + } + + private fun computeOffsets(document: Document, position: ScriptReport.Position): Pair { + val startLine = position.startLine.coerceLineIn(document) + val startOffset = document.offsetBy(startLine, position.startColumn) + + val endLine = position.endLine?.coerceAtLeast(startLine)?.coerceLineIn(document) ?: startLine + val endOffset = document.offsetBy( + endLine, + position.endColumn ?: document.getLineEndOffset(endLine) + ).coerceAtLeast(startOffset) + + return startOffset to endOffset + } + + private fun Int.coerceLineIn(document: Document) = coerceIn(0, document.lineCount - 1) + + private fun Document.offsetBy(line: Int, col: Int): Int { + return (getLineStartOffset(line) + col).coerceIn(getLineStartOffset(line), getLineEndOffset(line)) + } + + private fun ScriptReport.Severity.convertSeverity(): HighlightSeverity? { + return when (this) { + ScriptReport.Severity.FATAL -> ERROR + ScriptReport.Severity.ERROR -> ERROR + ScriptReport.Severity.WARNING -> WARNING + ScriptReport.Severity.INFO -> INFORMATION + ScriptReport.Severity.DEBUG -> if (ApplicationManager.getApplication().isInternal) INFORMATION else null + } + } + + private fun showNotification(file: KtFile, message: String) { + UIUtil.invokeLaterIfNeeded { + val ideFrame = WindowManager.getInstance().getIdeFrame(file.project) + if (ideFrame != null) { + val statusBar = ideFrame.statusBar as StatusBarEx + statusBar.notifyProgressByBalloon( + MessageType.WARNING, + message, + null, + null + ) + } + } + } + + class Factory(registrar: TextEditorHighlightingPassRegistrar) : ProjectComponent, + TextEditorHighlightingPassFactory { + init { + registrar.registerTextEditorHighlightingPass( + this, + TextEditorHighlightingPassRegistrar.Anchor.BEFORE, + Pass.UPDATE_FOLDING, + false, + false + ) + } + + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return ScriptExternalHighlightingPass(file, editor.document) + } + } +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt new file mode 100644 index 00000000000..b93d1bb11b5 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt @@ -0,0 +1,39 @@ +/* + * 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 + +import com.intellij.codeInsight.daemon.impl.SeverityRegistrar +import com.intellij.codeInsight.daemon.impl.TrafficLightRenderer +import com.intellij.codeInsight.daemon.impl.TrafficLightRendererContributor +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.psi.KtFile + +class ScriptTrafficLightRendererContributor : TrafficLightRendererContributor { + override fun createRenderer(editor: Editor, file: PsiFile?): TrafficLightRenderer? { + if ((file as? KtFile)?.isScript() == true) { + return ScriptTrafficLightRenderer(file.project, editor.document, file) + } + return null + } + + class ScriptTrafficLightRenderer(project: Project, document: Document, private val file: KtFile) : + TrafficLightRenderer(project, document, file) { + override fun getDaemonCodeAnalyzerStatus(severityRegistrar: SeverityRegistrar): DaemonCodeAnalyzerStatus { + val status = super.getDaemonCodeAnalyzerStatus(severityRegistrar) + if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) { + status.reasonWhySuspended = "Loading kotlin script definitions" + status.errorAnalyzingFinished = false + } else if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { + status.reasonWhySuspended = "Loading kotlin script dependencies" + status.errorAnalyzingFinished = false + } + return status + } + } +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt.182 b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt.182 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/resources/META-INF/plugin.xml b/idea/resources/META-INF/plugin.xml index 5da2d9c8e5b..e484676025a 100644 --- a/idea/resources/META-INF/plugin.xml +++ b/idea/resources/META-INF/plugin.xml @@ -81,5 +81,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + diff --git a/idea/resources/META-INF/plugin.xml.183 b/idea/resources/META-INF/plugin.xml.183 index 46a859286ca..11443b00275 100644 --- a/idea/resources/META-INF/plugin.xml.183 +++ b/idea/resources/META-INF/plugin.xml.183 @@ -73,4 +73,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + + diff --git a/idea/resources/META-INF/plugin.xml.192 b/idea/resources/META-INF/plugin.xml.192 index de956a8f77f..3878e993480 100644 --- a/idea/resources/META-INF/plugin.xml.192 +++ b/idea/resources/META-INF/plugin.xml.192 @@ -81,5 +81,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + diff --git a/idea/resources/META-INF/plugin.xml.as34 b/idea/resources/META-INF/plugin.xml.as34 index ab06e61fec6..7bf06a64e6d 100644 --- a/idea/resources/META-INF/plugin.xml.as34 +++ b/idea/resources/META-INF/plugin.xml.as34 @@ -72,4 +72,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + + diff --git a/idea/resources/META-INF/plugin.xml.as35 b/idea/resources/META-INF/plugin.xml.as35 index 8dccb87c479..86090c611b5 100644 --- a/idea/resources/META-INF/plugin.xml.as35 +++ b/idea/resources/META-INF/plugin.xml.as35 @@ -72,4 +72,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + +