diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt index 77c56492c1b..e2566d6c1fe 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt @@ -72,9 +72,4 @@ fun TextEditor.addScratchPanel(panel: ScratchTopPanel) { panel.scratchFile.project.syncPublisherWithDisposeCheck(ScratchPanelListener.TOPIC).panelAdded(panel) } -fun TextEditor.removeScratchPanel() { - scratchTopPanel?.let { FileEditorManager.getInstance(it.scratchFile.project).removeTopComponent(this, it.component) } - scratchTopPanel = null -} - private var TextEditor.scratchTopPanel: ScratchTopPanel? by UserDataProperty(Key.create("scratch.panel")) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchFileHook.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchFileHook.kt index 7da6f086b4c..644149e188a 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchFileHook.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchFileHook.kt @@ -16,13 +16,18 @@ package org.jetbrains.kotlin.idea.scratch.ui +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.ProjectComponent import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.fileEditor.TextEditor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager import org.jetbrains.kotlin.idea.scratch.* +import org.jetbrains.kotlin.idea.scratch.output.InlayScratchOutputHandler +import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter class ScratchFileHook(val project: Project) : ProjectComponent { @@ -30,17 +35,15 @@ class ScratchFileHook(val project: Project) : ProjectComponent { project.messageBus.connect(project).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, ScratchEditorListener()) } - override fun projectClosed() { - getAllEditorsWithScratchFiles(project).forEach { editor -> editor.removeScratchPanel() } - } - private inner class ScratchEditorListener : FileEditorManagerListener { override fun fileOpened(source: FileEditorManager, file: VirtualFile) { if (!isPluggable(file)) return val editor = getEditorWithoutScratchFile(source, file) ?: return - ScratchTopPanel.createPanel(project, file, editor) + val scratchFile = createScratchFile(project, file, editor) ?: return + val panel = ScratchTopPanel(scratchFile) + editor.addScratchPanel(panel) ScratchFileAutoRunner.addListener(project, editor) } @@ -55,3 +58,26 @@ class ScratchFileHook(val project: Project) : ProjectComponent { return ScratchFileLanguageProvider.get(psiFile.fileType) != null } } + +private fun createScratchFile(project: Project, file: VirtualFile, editor: TextEditor): ScratchFile? { + val psiFile = PsiManager.getInstance(project).findFile(file) ?: return null + val scratchFile = ScratchFileLanguageProvider.get(psiFile.language)?.newScratchFile(project, editor) ?: return null + setupReplRestartingOutputHandler(project, scratchFile) + + return scratchFile +} + +private fun setupReplRestartingOutputHandler(project: Project, scratchFile: ScratchFile) { + scratchFile.replScratchExecutor?.addOutputHandler(object : ScratchOutputHandlerAdapter() { + override fun onFinish(file: ScratchFile) { + ApplicationManager.getApplication().invokeLater { + if (!file.project.isDisposed) { + val scratch = file.getPsiFile() + if (scratch?.isValid == true) { + DaemonCodeAnalyzer.getInstance(project).restart(scratch) + } + } + } + } + }) +} diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt index 811745b030f..aa7ceadfa36 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt @@ -17,67 +17,22 @@ package org.jetbrains.kotlin.idea.scratch.ui -import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.* import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.TextEditor -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiManager import com.intellij.util.messages.Topic import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.idea.scratch.ScratchFile -import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction import org.jetbrains.kotlin.idea.scratch.actions.StopScratchAction -import org.jetbrains.kotlin.idea.scratch.addScratchPanel import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter -import org.jetbrains.kotlin.idea.scratch.removeScratchPanel import javax.swing.JComponent -class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : Disposable { +class ScratchTopPanel(val scratchFile: ScratchFile) : Disposable { override fun dispose() { scratchFile.replScratchExecutor?.stop() scratchFile.compilingScratchExecutor?.stop() - scratchFile.editor.removeScratchPanel() - } - - companion object { - fun createPanel(project: Project, virtualFile: VirtualFile, editor: TextEditor) { - val psiFile = PsiManager.getInstance(project).findFile(virtualFile) ?: return - val scratchFile = ScratchFileLanguageProvider.get(psiFile.language)?.newScratchFile(project, editor) ?: return - val panel = ScratchTopPanel(scratchFile) - - val toolbarHandler = createUpdateToolbarHandler(panel) - scratchFile.replScratchExecutor?.addOutputHandler(object : ScratchOutputHandlerAdapter() { - override fun onFinish(file: ScratchFile) { - ApplicationManager.getApplication().invokeLater { - if (!file.project.isDisposed) { - val scratch = file.getPsiFile() - if (scratch?.isValid == true) { - DaemonCodeAnalyzer.getInstance(project).restart(scratch) - } - } - } - } - }) - scratchFile.replScratchExecutor?.addOutputHandler(toolbarHandler) - scratchFile.compilingScratchExecutor?.addOutputHandler(toolbarHandler) - - editor.addScratchPanel(panel) - } - - private fun createUpdateToolbarHandler(panel: ScratchTopPanel) = object : ScratchOutputHandlerAdapter() { - override fun onStart(file: ScratchFile) { - panel.updateToolbar() - } - - override fun onFinish(file: ScratchFile) { - panel.updateToolbar() - } - } } private val moduleChooserAction: ModulesComboBoxAction = ModulesComboBoxAction(scratchFile) @@ -85,6 +40,7 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : Dispos init { scratchFile.addModuleListener { _, _ -> updateToolbar() } + setupTopPanelUpdateHandlers() val toolbarGroup = DefaultActionGroup().apply { add(RunScratchAction()) @@ -105,6 +61,24 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : Dispos val component: JComponent = actionsToolbar.component + private fun setupTopPanelUpdateHandlers() { + val toolbarHandler = createUpdateToolbarHandler() + scratchFile.replScratchExecutor?.addOutputHandler(toolbarHandler) + scratchFile.compilingScratchExecutor?.addOutputHandler(toolbarHandler) + } + + private fun createUpdateToolbarHandler(): ScratchOutputHandlerAdapter { + return object : ScratchOutputHandlerAdapter() { + override fun onStart(file: ScratchFile) { + updateToolbar() + } + + override fun onFinish(file: ScratchFile) { + updateToolbar() + } + } + } + @TestOnly fun setReplMode(isSelected: Boolean) { scratchFile.saveOptions { copy(isRepl = isSelected) }