diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt index d348d90eeba..c9c3eb927dd 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt @@ -68,7 +68,7 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent { val scratchPanel = getEditorWithScratchPanel(source, file)?.second scratchPanel?.addModuleListener { psiFile, module -> - psiFile.virtualFile.scriptRelatedModuleName = module.name + psiFile.virtualFile.scriptRelatedModuleName = module?.name // Drop caches for old module ScriptDependenciesModificationTracker.getInstance(project).incModificationCount() @@ -79,11 +79,6 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent { val module = ktFile.virtualFile.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } if (module != null) { scratchPanel?.setModule(module) - } else { - val firstModule = ModuleManager.getInstance(project).modules.firstOrNull() - if (firstModule != null) { - scratchPanel?.setModule(firstModule) - } } } } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt index 396c147b9ed..dc8abedc234 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt @@ -62,11 +62,6 @@ class RunScratchAction : ScratchAction( val module = scratchPanel.getModule() - @Suppress("FoldInitializerAndIfToElvis") - if (module == null) { - return defaultOutputHandler.error(scratchFile, "Module should be selected") - } - val executor = if (isRepl) provider.createReplExecutor(scratchFile) else provider.createCompilingExecutor(scratchFile) @Suppress("FoldInitializerAndIfToElvis") @@ -96,7 +91,7 @@ class RunScratchAction : ScratchAction( } } - if (!isAutoRun && isMakeBeforeRun) { + if (!isAutoRun && module != null && isMakeBeforeRun) { val project = scratchPanel.scratchFile.project ProjectTaskManager.getInstance(project).build(arrayOf(module)) { result -> if (result.isAborted || result.errors > 0) { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt index c8ead10d197..9963592c807 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager import org.jetbrains.kotlin.idea.debugger.DebuggerUtils import org.jetbrains.kotlin.idea.refactoring.getLineNumber import org.jetbrains.kotlin.idea.scratch.* @@ -63,7 +64,7 @@ class KtCompilingExecutor(file: ScratchFile) : ScratchExecutor(file) { override fun execute() { handler.onStart(file) - val module = file.getModule() ?: return errorOccurs("Module should be selected", isFatal = true) + val module = file.getModule() val psiFile = file.getPsiFile() as? KtFile ?: return errorOccurs("Couldn't find KtFile for current editor", isFatal = true) if (!checkForErrors(psiFile)) return @@ -90,7 +91,7 @@ class KtCompilingExecutor(file: ScratchFile) : ScratchExecutor(file) { ) ?: return try { - val commandLine = createCommandLine(module, result.mainClassName, tempDir.path) + val commandLine = createCommandLine(psiFile, module, result.mainClassName, tempDir.path) LOG.printDebugMessage(commandLine.commandLineString) @@ -176,16 +177,22 @@ class KtCompilingExecutor(file: ScratchFile) : ScratchExecutor(file) { return dir } - private fun createCommandLine(module: Module, mainClassName: String, tempOutDir: String): GeneralCommandLine { + private fun createCommandLine(originalFile: KtFile, module: Module?, mainClassName: String, tempOutDir: String): GeneralCommandLine { val javaParameters = KotlinConsoleKeeper.createJavaParametersWithSdk(module) javaParameters.mainClass = mainClassName - val compiledModulePath = CompilerPathsEx.getOutputPaths(arrayOf(module)).toList() - val moduleDependencies = OrderEnumerator.orderEntries(module).recursively().pathsList.pathList - javaParameters.classPath.add(tempOutDir) - javaParameters.classPath.addAll(compiledModulePath) - javaParameters.classPath.addAll(moduleDependencies) + + if (module != null) { + val compiledModulePath = CompilerPathsEx.getOutputPaths(arrayOf(module)).toList() + javaParameters.classPath.addAll(compiledModulePath) + + val moduleDependencies = OrderEnumerator.orderEntries(module).recursively().pathsList.pathList + javaParameters.classPath.addAll(moduleDependencies) + } + + val scriptDependencies = ScriptDependenciesManager.getInstance(originalFile.project).getScriptDependencies(originalFile.virtualFile) + javaParameters.classPath.addAll(scriptDependencies.classpath.map { it.absolutePath }) return javaParameters.toCommandLine() } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt index daaf7f11965..8d93d616a26 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt @@ -43,7 +43,7 @@ class KtScratchReplExecutor(file: ScratchFile) : ScratchExecutor(file) { override fun execute() { handler.onStart(file) - val module = file.getModule() ?: return errorOccurs("Module should be selected", isFatal = true) + val module = file.getModule() val cmdLine = KotlinConsoleKeeper.createCommandLine(module) LOG.printDebugMessage("Execute REPL: ${cmdLine.commandLineString}") 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 0442632c187..983cad87aa8 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 @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.scratch.ui import com.intellij.application.options.ModulesComboBox +import com.intellij.execution.ui.ConfigurationModuleSelector import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces @@ -115,11 +116,11 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel moduleChooser.selectedModule = module } - fun addModuleListener(f: (PsiFile, Module) -> Unit) { + fun addModuleListener(f: (PsiFile, Module?) -> Unit) { moduleChooser.addActionListener { val selectedModule = moduleChooser.selectedModule val psiFile = scratchFile.getPsiFile() - if (selectedModule != null && psiFile != null) { + if (psiFile != null) { f(psiFile, selectedModule) } } @@ -162,6 +163,7 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel setModules(ModuleManager.getInstance(project).modules.filter { it.productionSourceInfo() != null || it.testSourceInfo() != null }) + allowEmptySelection(ConfigurationModuleSelector.NO_MODULE_TEXT) } } } \ No newline at end of file diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt index 117a1e9abed..162d6e9e411 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt @@ -54,7 +54,7 @@ class KotlinConsoleKeeper(val project: Project) { companion object { @JvmStatic fun getInstance(project: Project) = ServiceManager.getService(project, KotlinConsoleKeeper::class.java) - fun createCommandLine(module: Module): GeneralCommandLine { + fun createCommandLine(module: Module?): GeneralCommandLine { val javaParameters = createJavaParametersWithSdk(module) javaParameters.mainClass = "dummy" @@ -79,16 +79,18 @@ class KotlinConsoleKeeper(val project: Project) { paramList.add("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler") - addPathToCompiledOutput(paramList, module) + if (module != null) { + addPathToCompiledOutput(paramList, module) + } return commandLine } - fun createJavaParametersWithSdk(module: Module): JavaParameters { + fun createJavaParametersWithSdk(module: Module?): JavaParameters { val params = JavaParameters() params.charset = null - val sdk = ModuleRootManager.getInstance(module).sdk + val sdk = module?.let { ModuleRootManager.getInstance(module).sdk } if (sdk != null && sdk.sdkType is JavaSdkType && File(sdk.homePath).exists()) { params.jdk = sdk } diff --git a/idea/testData/scratch/simpleNoRuntime.comp.after b/idea/testData/scratch/simpleNoRuntime.comp.after new file mode 100644 index 00000000000..1b2688f68a9 --- /dev/null +++ b/idea/testData/scratch/simpleNoRuntime.comp.after @@ -0,0 +1,3 @@ +arrayListOf(1, 2).size // RESULT: 2 + +//NO_MODULE \ No newline at end of file diff --git a/idea/testData/scratch/simpleNoRuntime.kts b/idea/testData/scratch/simpleNoRuntime.kts new file mode 100644 index 00000000000..f39820c5a5d --- /dev/null +++ b/idea/testData/scratch/simpleNoRuntime.kts @@ -0,0 +1,3 @@ +arrayListOf(1, 2).size + +//NO_MODULE \ No newline at end of file diff --git a/idea/testData/scratch/simpleNoRuntime.repl.after b/idea/testData/scratch/simpleNoRuntime.repl.after new file mode 100644 index 00000000000..027127cf60c --- /dev/null +++ b/idea/testData/scratch/simpleNoRuntime.repl.after @@ -0,0 +1,3 @@ +arrayListOf(1, 2).size // RESULT: res0: kotlin.Int = 2 + +//NO_MODULE \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt index 9a91c184697..9e03e25946b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt @@ -12,6 +12,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.roots.CompilerModuleExtension import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.psi.PsiDocumentManager @@ -27,9 +28,11 @@ import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction import org.jetbrains.kotlin.idea.scratch.actions.ScratchCompilationSupport import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer +import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.MockLibraryUtil import org.junit.Assert @@ -100,11 +103,15 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { if (!KotlinHighlightingUtil.shouldHighlight(psiFile)) error("Highlighting for scratch file is switched off") - 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 { copy(isRepl = isRepl, isInteractiveMode = false) } + if (!InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) { + scratchPanel.setModule(myFixture.module) + } + launchScratch(scratchFile) UIUtil.dispatchAllInvocationEvents() @@ -128,7 +135,10 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { .filterIsInstance() .forEach { val str = it.toString() - val offset = doc.getLineEndOffset(line); actualOutput.insert(offset, "${str.takeWhile { it.isWhitespace() }}// ${str.trim()}") + val offset = doc.getLineEndOffset(line); actualOutput.insert( + offset, + "${str.takeWhile { it.isWhitespace() }}// ${str.trim()}" + ) } } @@ -160,7 +170,15 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory() - override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK + + override fun getProjectDescriptor(): com.intellij.testFramework.LightProjectDescriptor { + val testName = StringUtil.toLowerCase(getTestName(false)) + + return when { + testName.endsWith("NoRuntime") -> KotlinLightProjectDescriptor.INSTANCE + else -> KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK + } + } override fun setUp() { super.setUp() diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java index 033a0aad7a9..465d93860f0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java @@ -56,6 +56,11 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest runTest("idea/testData/scratch/simpleFun.kts"); } + @TestMetadata("simpleNoRuntime.kts") + public void testSimpleNoRuntime() throws Exception { + runTest("idea/testData/scratch/simpleNoRuntime.kts"); + } + @TestMetadata("spacesAtLineStart.kts") public void testSpacesAtLineStart() throws Exception { runTest("idea/testData/scratch/spacesAtLineStart.kts"); @@ -134,6 +139,11 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest runTest("idea/testData/scratch/simpleFun.kts"); } + @TestMetadata("simpleNoRuntime.kts") + public void testSimpleNoRuntime() throws Exception { + runTest("idea/testData/scratch/simpleNoRuntime.kts"); + } + @TestMetadata("spacesAtLineStart.kts") public void testSpacesAtLineStart() throws Exception { runTest("idea/testData/scratch/spacesAtLineStart.kts");