diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt index 243f57f259f..6f26e039c53 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt @@ -29,6 +29,8 @@ import com.intellij.openapi.editor.markup.* import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.psi.PsiManager +import com.intellij.util.Consumer +import org.jetbrains.kotlin.console.actions.BuildAndRestartConsoleAction import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction import org.jetbrains.kotlin.console.gutter.KotlinConsoleGutterContentProvider import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer @@ -83,7 +85,9 @@ public class KotlinConsoleRunner( keeper.putVirtualFileToConsole(consoleFile, this) processHandler.addProcessListener(object : ProcessAdapter() { - override fun processTerminated(_: ProcessEvent) { keeper.removeConsole(consoleFile) } + override fun processTerminated(_: ProcessEvent) { + keeper.removeConsole(consoleFile) + } }) return processHandler @@ -98,15 +102,22 @@ public class KotlinConsoleRunner( contentDescriptor: RunContentDescriptor ): List { val actionList = arrayListOf( - createCloseAction(defaultExecutor, contentDescriptor), - createConsoleExecAction(consoleExecuteActionHandler) + BuildAndRestartConsoleAction(project, module, defaultExecutor, contentDescriptor, restarter), + createConsoleExecAction(consoleExecuteActionHandler), + createCloseAction(defaultExecutor, contentDescriptor) ) toolbarActions.addAll(actionList) return actionList } override fun createConsoleExecAction(consoleExecuteActionHandler: ProcessBackedConsoleExecuteActionHandler) - = ConsoleExecuteAction(consoleView, consoleExecuteActionHandler, "KotlinShellExecute", consoleExecuteActionHandler) + = ConsoleExecuteAction(consoleView, consoleExecuteActionHandler, "KotlinShellExecute", consoleExecuteActionHandler) + + private val restarter = object : Consumer { + override fun consume(module: Module) { + KotlinConsoleKeeper.getInstance(project).run(module) + } + } private fun setupPlaceholder(editor: EditorEx) { editor.setPlaceholder(" to execute") diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/BuildAndRestartConsoleAction.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/BuildAndRestartConsoleAction.kt new file mode 100644 index 00000000000..34beaf640b2 --- /dev/null +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/BuildAndRestartConsoleAction.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2010-2015 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.console.actions + +import com.intellij.execution.ExecutionManager +import com.intellij.execution.Executor +import com.intellij.execution.ui.RunContentDescriptor +import com.intellij.icons.AllIcons +import com.intellij.notification.Notification +import com.intellij.notification.NotificationListener +import com.intellij.notification.NotificationType +import com.intellij.notification.Notifications +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.compiler.CompileContext +import com.intellij.openapi.compiler.CompileStatusNotification +import com.intellij.openapi.compiler.CompilerManager +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.util.Consumer +import javax.swing.event.HyperlinkEvent + +private fun buildAndRestartMessage(module: Module) = "Build module '${module.name}' and restart" + +public class BuildAndRestartConsoleAction( + private val project: Project, + private val module: Module, + private val executor: Executor, + private val contentDescriptor: RunContentDescriptor, + private val restarter: Consumer +) : AnAction("Build and restart", buildAndRestartMessage(module), AllIcons.Actions.Restart) { + + init { + showOutdatedClassedNotificationIfNeeded() + } + + override fun actionPerformed(_: AnActionEvent) = compileModule() + + private fun compileModule() { + if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) { + CompilerManager.getInstance(project).make(module, object : CompileStatusNotification { + override fun finished(aborted: Boolean, errors: Int, warnings: Int, compileContext: CompileContext): Unit + = if (!module.isDisposed) restarter.consume(module) + }) + } + } + + private fun showOutdatedClassedNotificationIfNeeded() { + val compilerManager = CompilerManager.getInstance(project) + val compilerScope = compilerManager.createModuleCompileScope(module, true) + if (compilerManager.isUpToDate(compilerScope)) return + + val warningTag = "KOTLIN REPL WARNING" + val warningTitle = "Kotlin REPL Configuration Warning" + + val hyperlinkListener = object : NotificationListener { + override fun hyperlinkUpdate(notification: Notification, event: HyperlinkEvent) { + if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) { + compileModule() + notification.expire() + } + } + } + + Notifications.Bus.notify( + Notification( + warningTag, warningTitle, + "You’re running the REPL with outdated classes
${buildAndRestartMessage(module)}", + NotificationType.WARNING, + hyperlinkListener + ), + project + ) + } +} \ No newline at end of file