Scratch: implement interactive mode

^KT-27955 Fixed
This commit is contained in:
Natalia Selezneva
2019-01-17 10:49:26 +03:00
parent 9b0b3971e4
commit 290ae16235
14 changed files with 249 additions and 62 deletions
@@ -22,12 +22,16 @@ import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.refactoring.getLineNumber import org.jetbrains.kotlin.idea.refactoring.getLineNumber
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.resolve.AnalyzingUtils
class KtScratchFile(project: Project, editor: TextEditor) : ScratchFile(project, editor) { class KtScratchFile(project: Project, editor: TextEditor) : ScratchFile(project, editor) {
override fun getExpressions(psiFile: PsiFile): List<ScratchExpression> { override fun getExpressions(psiFile: PsiFile): List<ScratchExpression> {
@@ -60,4 +64,14 @@ class KtScratchFile(project: Project, editor: TextEditor) : ScratchFile(project,
return result return result
} }
override fun hasErrors(): Boolean {
val psiFile = getPsiFile() as? KtFile ?: return false
try {
AnalyzingUtils.checkForSyntacticErrors(psiFile)
} catch (e: IllegalArgumentException) {
return true
}
return psiFile.analyzeWithContent().diagnostics.any { it.severity == Severity.ERROR }
}
} }
@@ -50,11 +50,13 @@ abstract class ScratchFile(val project: Project, val editor: TextEditor) {
} }
abstract fun getExpressions(psiFile: PsiFile): List<ScratchExpression> abstract fun getExpressions(psiFile: PsiFile): List<ScratchExpression>
abstract fun hasErrors(): Boolean
} }
data class ScratchExpression(val element: PsiElement, val lineStart: Int, val lineEnd: Int = lineStart) data class ScratchExpression(val element: PsiElement, val lineStart: Int, val lineEnd: Int = lineStart)
data class ScratchFileOptions( data class ScratchFileOptions(
val isRepl: Boolean = false, val isRepl: Boolean = false,
val isMakeBeforeRun: Boolean = false val isMakeBeforeRun: Boolean = false,
val isInteractiveMode: Boolean = true
) )
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.scratch
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.Alarm
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
import org.jetbrains.kotlin.idea.scratch.actions.ScratchCompilationSupport
import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
class ScratchFileAutoRunner(private val project: Project) : DocumentListener {
companion object {
fun addListener(project: Project, editor: TextEditor) {
if (editor.getScratchPanel() != null) {
editor.editor.document.addDocumentListener(getInstance(project))
Disposer.register(editor, Disposable {
editor.editor.document.removeDocumentListener(getInstance(project))
})
}
}
private fun getInstance(project: Project) = ServiceManager.getService(project, ScratchFileAutoRunner::class.java)
private const val auto_run_delay = 2000
}
private val myAlarm = Alarm(Alarm.ThreadToUse.SWING_THREAD, project)
override fun documentChanged(event: DocumentEvent) {
val file = FileDocumentManager.getInstance().getFile(event.document) ?: return
if (project.isDisposed) return
val panel = getScratchPanel(file, project) ?: return
if (!panel.scratchFile.options.isInteractiveMode) return
if (isScratchChanged(project, file)) {
runScratch(panel)
}
}
private fun runScratch(panel: ScratchTopPanel) {
myAlarm.cancelAllRequests()
if (ScratchCompilationSupport.isInProgress(panel.scratchFile)) {
ScratchCompilationSupport.forceStop()
}
myAlarm.addRequest(
{
val psiFile = panel.scratchFile.getPsiFile()
if (psiFile != null && psiFile.isValid && !panel.scratchFile.hasErrors()) {
RunScratchAction.doAction(panel, true)
}
}, auto_run_delay, true
)
}
private fun getScratchPanel(file: VirtualFile, project: Project): ScratchTopPanel? {
return getEditorWithScratchPanel(FileEditorManager.getInstance(project), file)?.second
}
}
@@ -25,6 +25,7 @@ import com.intellij.task.ProjectTaskManager
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.scratch.* import org.jetbrains.kotlin.idea.scratch.*
import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter
import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
import org.jetbrains.kotlin.idea.scratch.LOG as log import org.jetbrains.kotlin.idea.scratch.LOG as log
class RunScratchAction : ScratchAction( class RunScratchAction : ScratchAction(
@@ -42,70 +43,77 @@ class RunScratchAction : ScratchAction(
val project = e.project ?: return val project = e.project ?: return
val scratchPanel = getScratchPanelFromSelectedEditor(project) ?: return val scratchPanel = getScratchPanelFromSelectedEditor(project) ?: return
val scratchFile = scratchPanel.scratchFile doAction(scratchPanel, false)
val psiFile = scratchFile.getPsiFile() ?: return }
companion object {
fun doAction(scratchPanel: ScratchTopPanel, isAutoRun: Boolean) {
val scratchFile = scratchPanel.scratchFile
val psiFile = scratchFile.getPsiFile() ?: return
val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun
val isRepl = scratchFile.options.isRepl val isRepl = scratchFile.options.isRepl
val provider = ScratchFileLanguageProvider.get(psiFile.language) ?: return val provider = ScratchFileLanguageProvider.get(psiFile.language) ?: return
log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun, isRepl = $isRepl") log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun, isRepl = $isRepl")
val defaultOutputHandler = provider.getOutputHandler() val defaultOutputHandler = provider.getOutputHandler()
val module = scratchPanel.getModule() val module = scratchPanel.getModule()
@Suppress("FoldInitializerAndIfToElvis") @Suppress("FoldInitializerAndIfToElvis")
if (module == null) { if (module == null) {
return defaultOutputHandler.error(scratchFile, "Module should be selected") return defaultOutputHandler.error(scratchFile, "Module should be selected")
}
val executor = if (isRepl) provider.createReplExecutor(scratchFile) else provider.createCompilingExecutor(scratchFile)
@Suppress("FoldInitializerAndIfToElvis")
if (executor == null) {
return defaultOutputHandler.error(scratchFile, "Couldn't run ${psiFile.name}")
}
executor.addOutputHandler(defaultOutputHandler)
executor.addOutputHandler(object : ScratchOutputHandlerAdapter() {
override fun onStart(file: ScratchFile) {
ScratchCompilationSupport.start(file, executor)
scratchPanel.updateToolbar()
} }
override fun onFinish(file: ScratchFile) { val executor = if (isRepl) provider.createReplExecutor(scratchFile) else provider.createCompilingExecutor(scratchFile)
ScratchCompilationSupport.stop()
scratchPanel.updateToolbar()
}
})
fun executeScratch() { @Suppress("FoldInitializerAndIfToElvis")
try { if (executor == null) {
executor.execute() return defaultOutputHandler.error(scratchFile, "Couldn't run ${psiFile.name}")
} catch (ex: Throwable) {
executor.errorOccurs("Exception occurs during Run Scratch Action", ex, true)
} }
}
if (isMakeBeforeRun) { executor.addOutputHandler(defaultOutputHandler)
ProjectTaskManager.getInstance(project).build(arrayOf(module)) { result ->
if (result.isAborted || result.errors > 0) { executor.addOutputHandler(object : ScratchOutputHandlerAdapter() {
executor.errorOccurs("There were compilation errors in module ${module.name}") override fun onStart(file: ScratchFile) {
ScratchCompilationSupport.start(file, executor)
scratchPanel.updateToolbar()
} }
if (DumbService.isDumb(project)) { override fun onFinish(file: ScratchFile) {
DumbService.getInstance(project).smartInvokeLater { ScratchCompilationSupport.stop()
scratchPanel.updateToolbar()
}
})
fun executeScratch() {
try {
executor.execute()
} catch (ex: Throwable) {
executor.errorOccurs("Exception occurs during Run Scratch Action", ex, true)
}
}
if (!isAutoRun && isMakeBeforeRun) {
val project = scratchPanel.scratchFile.project
ProjectTaskManager.getInstance(project).build(arrayOf(module)) { result ->
if (result.isAborted || result.errors > 0) {
executor.errorOccurs("There were compilation errors in module ${module.name}")
}
if (DumbService.isDumb(project)) {
DumbService.getInstance(project).smartInvokeLater {
executeScratch()
}
} else {
executeScratch() executeScratch()
} }
} else {
executeScratch()
} }
} else {
executeScratch()
} }
} else {
executeScratch()
} }
} }
@@ -18,8 +18,10 @@ package org.jetbrains.kotlin.idea.scratch.output
import com.intellij.execution.filters.OpenFileHyperlinkInfo import com.intellij.execution.filters.OpenFileHyperlinkInfo
import com.intellij.execution.impl.ConsoleViewImpl import com.intellij.execution.impl.ConsoleViewImpl
import com.intellij.execution.runners.ExecutionUtil
import com.intellij.execution.ui.ConsoleViewContentType import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.ide.scratch.ScratchFileType import com.intellij.ide.scratch.ScratchFileType
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.ex.EditorEx
@@ -47,7 +49,7 @@ fun getToolwindowHandler(): ScratchOutputHandler {
private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() { private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() {
override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) { override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
printToConsole(file.project) { printToConsole(file) {
val psiFile = file.getPsiFile() val psiFile = file.getPsiFile()
if (psiFile != null) { if (psiFile != null) {
printHyperlink( printHyperlink(
@@ -65,14 +67,17 @@ private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() {
} }
override fun error(file: ScratchFile, message: String) { override fun error(file: ScratchFile, message: String) {
printToConsole(file.project) { printToConsole(file) {
print(message, ConsoleViewContentType.ERROR_OUTPUT) print(message, ConsoleViewContentType.ERROR_OUTPUT)
} }
} }
private fun printToConsole(project: Project, print: ConsoleViewImpl.() -> Unit) { private fun printToConsole(file: ScratchFile, print: ConsoleViewImpl.() -> Unit) {
ApplicationManager.getApplication().invokeLater { ApplicationManager.getApplication().invokeLater {
val toolWindow = getToolWindow(project) ?: createToolWindow(project) val project = file.project.takeIf { !it.isDisposed } ?: return@invokeLater
val toolWindow = getToolWindow(project) ?: createToolWindow(file)
val contents = toolWindow.contentManager.contents val contents = toolWindow.contentManager.contents
for (content in contents) { for (content in contents) {
val component = content.component val component = content.component
@@ -81,8 +86,14 @@ private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() {
component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT) component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT)
} }
} }
toolWindow.setAvailable(true, null) toolWindow.setAvailable(true, null)
toolWindow.show(null)
if (!file.options.isInteractiveMode) {
toolWindow.show(null)
}
toolWindow.icon = ExecutionUtil.getLiveIndicator(ScratchFileType.INSTANCE.icon)
} }
} }
@@ -96,8 +107,12 @@ private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() {
component.clear() component.clear()
} }
} }
toolWindow.setAvailable(false, null)
toolWindow.hide(null) if (!file.options.isInteractiveMode) {
toolWindow.hide(null)
}
toolWindow.icon = ScratchFileType.INSTANCE.icon
} }
} }
@@ -112,11 +127,17 @@ private object ToolWindowScratchOutputHandler : ScratchOutputHandlerAdapter() {
return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID) return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
} }
private fun createToolWindow(project: Project): ToolWindow { private fun createToolWindow(file: ScratchFile): ToolWindow {
val project = file.project
val toolWindowManager = ToolWindowManager.getInstance(project) val toolWindowManager = ToolWindowManager.getInstance(project)
toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM) toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID) val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
ScratchToolWindowFactory().createToolWindowContent(project, window) ScratchToolWindowFactory().createToolWindowContent(project, window)
Disposer.register(file.editor, Disposable {
window.setAvailable(false, null)
})
return window return window
} }
} }
@@ -133,6 +154,7 @@ private class ScratchToolWindowFactory : ToolWindowFactory {
val consoleView = ConsoleViewImpl(project, true) val consoleView = ConsoleViewImpl(project, true)
toolWindow.isToHideOnEmptyContent = true toolWindow.isToHideOnEmptyContent = true
toolWindow.icon = ScratchFileType.INSTANCE.icon toolWindow.icon = ScratchFileType.INSTANCE.icon
toolWindow.hide(null)
val contentManager = toolWindow.contentManager val contentManager = toolWindow.contentManager
val content = contentManager.factory.createContent(consoleView.component, null, false) val content = contentManager.factory.createContent(consoleView.component, null, false)
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.scratch
import com.intellij.openapi.externalSystem.service.project.autoimport.ConfigurationFileCrcFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.psi.UserDataProperty
fun isScratchChanged(project: Project, file: VirtualFile) : Boolean {
val beforeLastRun = file.crcWithoutSpaces
val newCrc = ConfigurationFileCrcFactory(project, file).create()
if (beforeLastRun != newCrc) {
file.crcWithoutSpaces = newCrc
return true
}
return false
}
private var VirtualFile.crcWithoutSpaces by UserDataProperty(Key.create<Long>("CRC_WITHOUT_SPACES"))
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.scratch
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
fun isScratchChanged(project: Project, file: VirtualFile) : Boolean {
return true
}
@@ -10,11 +10,12 @@ import org.jetbrains.kotlin.idea.core.util.cachedFileAttribute
import org.jetbrains.kotlin.idea.scratch.ScratchFileOptions import org.jetbrains.kotlin.idea.scratch.ScratchFileOptions
var VirtualFile.scratchFileOptions: ScratchFileOptions? by cachedFileAttribute( var VirtualFile.scratchFileOptions: ScratchFileOptions? by cachedFileAttribute(
name = "kotlin-scratch-panel-config", name = "kotlin-scratch-file-options",
version = 1, version = 1,
read = { ScratchFileOptions(readBoolean(), readBoolean()) }, read = { ScratchFileOptions(readBoolean(), readBoolean(), readBoolean()) },
write = { write = {
writeBoolean(it.isRepl) writeBoolean(it.isRepl)
writeBoolean(it.isMakeBeforeRun) writeBoolean(it.isMakeBeforeRun)
writeBoolean(it.isInteractiveMode)
} }
) )
@@ -24,10 +24,7 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider import org.jetbrains.kotlin.idea.scratch.*
import org.jetbrains.kotlin.idea.scratch.getAllEditorsWithScratchPanel
import org.jetbrains.kotlin.idea.scratch.getEditorWithoutScratchPanel
import org.jetbrains.kotlin.idea.scratch.removeScratchPanel
class ScratchFileHook(val project: Project) : ProjectComponent { class ScratchFileHook(val project: Project) : ProjectComponent {
@@ -46,6 +43,8 @@ class ScratchFileHook(val project: Project) : ProjectComponent {
val editor = getEditorWithoutScratchPanel(source, file) ?: return val editor = getEditorWithoutScratchPanel(source, file) ?: return
ScratchTopPanel.createPanel(project, file, editor) ScratchTopPanel.createPanel(project, file, editor)
ScratchFileAutoRunner.addListener(project, editor)
} }
override fun fileClosed(source: FileEditorManager, file: VirtualFile) {} override fun fileClosed(source: FileEditorManager, file: VirtualFile) {}
@@ -60,6 +60,7 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
private val moduleChooser: ModulesComboBox private val moduleChooser: ModulesComboBox
private val isReplCheckbox: JCheckBox private val isReplCheckbox: JCheckBox
private val isMakeBeforeRunCheckbox: JCheckBox private val isMakeBeforeRunCheckbox: JCheckBox
private val isInteractiveCheckbox: JCheckBox
private val actionsToolbar: ActionToolbar private val actionsToolbar: ActionToolbar
@@ -81,6 +82,16 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
add(JSeparator(SwingConstants.VERTICAL)) add(JSeparator(SwingConstants.VERTICAL))
isInteractiveCheckbox = JCheckBox("Interactive mode")
add(isInteractiveCheckbox)
isInteractiveCheckbox.addItemListener {
scratchFile.saveOptions {
copy(isInteractiveMode = isInteractiveCheckbox.isSelected)
}
}
add(JSeparator(SwingConstants.VERTICAL))
isReplCheckbox = JCheckBox("Use REPL") isReplCheckbox = JCheckBox("Use REPL")
add(isReplCheckbox) add(isReplCheckbox)
isReplCheckbox.addItemListener { isReplCheckbox.addItemListener {
@@ -94,6 +105,7 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
scratchFile.options.let { scratchFile.options.let {
isReplCheckbox.isSelected = it.isRepl isReplCheckbox.isSelected = it.isRepl
isMakeBeforeRunCheckbox.isSelected = it.isMakeBeforeRun isMakeBeforeRunCheckbox.isSelected = it.isMakeBeforeRun
isInteractiveCheckbox.isSelected = it.isInteractiveMode
} }
} }
@@ -123,6 +135,11 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
isMakeBeforeRunCheckbox.isSelected = isSelected isMakeBeforeRunCheckbox.isSelected = isSelected
} }
@TestOnly
fun setInteractiveMode(isSelected: Boolean) {
isInteractiveCheckbox.isSelected = isSelected
}
fun updateToolbar() { fun updateToolbar() {
ApplicationManager.getApplication().invokeLater { ApplicationManager.getApplication().invokeLater {
actionsToolbar.updateActionsImmediately() actionsToolbar.updateActionsImmediately()
+3
View File
@@ -72,6 +72,9 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches" <projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/> serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"
serviceImplementation="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/> <debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
+3
View File
@@ -72,6 +72,9 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches" <projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/> serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"
serviceImplementation="org.jetbrains.kotlin.idea.scratch.ScratchFileAutoRunner"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
<debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/> <debugger.jvmSmartStepIntoHandler implementation="org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler"/>
@@ -113,7 +113,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
val (editor, scratchPanel) = getEditorWithScratchPanel(myManager, scratchFile)?: error("Couldn't find scratch panel") val (editor, scratchPanel) = getEditorWithScratchPanel(myManager, scratchFile)?: error("Couldn't find scratch panel")
scratchPanel.scratchFile.saveOptions { scratchPanel.scratchFile.saveOptions {
copy(isRepl = isRepl) copy(isRepl = isRepl, isInteractiveMode = false)
} }
launchScratch(scratchFile) launchScratch(scratchFile)
@@ -33,14 +33,17 @@ class ScratchOptionsSaveTest : AbstractScratchRunActionTest() {
Assert.assertEquals( Assert.assertEquals(
"This test checks that checkbox options are restored after file closing. Not all checkboxes are checked in this test", "This test checks that checkbox options are restored after file closing. Not all checkboxes are checked in this test",
2, 3,
ScratchTopPanel::class.declaredMemberProperties.filter { it.returnType == JCheckBox::class.createType() }.size ScratchTopPanel::class.declaredMemberProperties.filter { it.returnType == JCheckBox::class.createType() }.size
) )
val newIsReplValue = !scratchPanelBeforeClosingFile.scratchFile.options.isRepl val newIsReplValue = !scratchPanelBeforeClosingFile.scratchFile.options.isRepl
val newIsMakeBeforeRunValue = !scratchPanelBeforeClosingFile.scratchFile.options.isMakeBeforeRun val newIsMakeBeforeRunValue = !scratchPanelBeforeClosingFile.scratchFile.options.isMakeBeforeRun
val newIsInteractiveModeValue = !scratchPanelBeforeClosingFile.scratchFile.options.isInteractiveMode
scratchPanelBeforeClosingFile.setReplMode(newIsReplValue) scratchPanelBeforeClosingFile.setReplMode(newIsReplValue)
scratchPanelBeforeClosingFile.setMakeBeforeRun(newIsMakeBeforeRunValue) scratchPanelBeforeClosingFile.setMakeBeforeRun(newIsMakeBeforeRunValue)
scratchPanelBeforeClosingFile.setInteractiveMode(newIsInteractiveModeValue)
myManager.closeFile(scratchFile) myManager.closeFile(scratchFile)
myManager.openFile(scratchFile, true) myManager.openFile(scratchFile, true)
@@ -53,5 +56,10 @@ class ScratchOptionsSaveTest : AbstractScratchRunActionTest() {
newIsMakeBeforeRunValue, newIsMakeBeforeRunValue,
scratchPanelAfterClosingFile.scratchFile.options.isMakeBeforeRun scratchPanelAfterClosingFile.scratchFile.options.isMakeBeforeRun
) )
Assert.assertEquals(
"Wrong value for isInteractiveMode checkbox",
newIsInteractiveModeValue,
scratchPanelAfterClosingFile.scratchFile.options.isInteractiveMode
)
} }
} }