KT-32366: Refactor scratchUtils to use mostly ScratchFile

- it is done to remove dependency from the UI component `ScratchTopPanel`
- occasional use of `ScratchTopPanel` is still left (for tests mostly)
This commit is contained in:
Roman Golyshev
2019-08-16 16:54:59 +03:00
committed by Roman Golyshev
parent 6c35c40bb9
commit 70e6f738eb
12 changed files with 66 additions and 70 deletions
@@ -19,12 +19,11 @@ import com.intellij.util.Alarm
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchFromHereAction
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) {
if (editor.getScratchFile() != null) {
editor.editor.document.addDocumentListener(getInstance(project))
Disposer.register(editor, Disposable {
editor.editor.document.removeDocumentListener(getInstance(project))
@@ -43,11 +42,11 @@ class ScratchFileAutoRunner(private val project: Project) : DocumentListener {
val file = FileDocumentManager.getInstance().getFile(event.document) ?: return
if (project.isDisposed) return
val panel = getScratchPanel(file, project) ?: return
if (!panel.scratchFile.options.isInteractiveMode) return
val scratchFile = getScratchFile(file, project) ?: return
if (!scratchFile.options.isInteractiveMode) return
if (!event.newFragment.isBlank()) {
runScratch(panel.scratchFile)
runScratch(scratchFile)
}
}
@@ -72,7 +71,7 @@ class ScratchFileAutoRunner(private val project: Project) : DocumentListener {
)
}
private fun getScratchPanel(file: VirtualFile, project: Project): ScratchTopPanel? {
return getEditorWithScratchPanel(FileEditorManager.getInstance(project), file)?.second
private fun getScratchFile(file: VirtualFile, project: Project): ScratchFile? {
return getScratchFileFromEditorSelectedForFile(FileEditorManager.getInstance(project), file)
}
}
@@ -20,7 +20,7 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.AnActionEvent
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
import org.jetbrains.kotlin.idea.scratch.getScratchFileFromSelectedEditor
class ClearScratchAction : ScratchAction(
KotlinBundle.message("scratch.clear.button"),
@@ -28,7 +28,7 @@ class ClearScratchAction : ScratchAction(
) {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val scratchFile = getScratchPanelFromSelectedEditor(project)?.scratchFile ?: return
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
val psiFile = scratchFile.getPsiFile() ?: return
ScratchFileLanguageProvider.get(psiFile.language)?.getOutputHandler()?.clear(scratchFile)
@@ -23,9 +23,7 @@ import com.intellij.openapi.keymap.KeymapUtil
import com.intellij.openapi.project.DumbService
import com.intellij.task.ProjectTaskManager
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.scratch.ScratchFile
import org.jetbrains.kotlin.idea.scratch.SequentialScratchExecutor
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
import org.jetbrains.kotlin.idea.scratch.*
import org.jetbrains.kotlin.idea.scratch.printDebugMessage
import org.jetbrains.kotlin.idea.scratch.LOG as log
@@ -42,9 +40,9 @@ class RunScratchAction : ScratchAction(
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val scratchPanel = getScratchPanelFromSelectedEditor(project) ?: return
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
doAction(scratchPanel.scratchFile, false)
doAction(scratchFile, false)
}
companion object {
@@ -105,8 +103,8 @@ class RunScratchAction : ScratchAction(
}
val project = e.project ?: return
val panel = getScratchPanelFromSelectedEditor(project) ?: return
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
e.presentation.isVisible = !ScratchCompilationSupport.isInProgress(panel.scratchFile)
e.presentation.isVisible = !ScratchCompilationSupport.isInProgress(scratchFile)
}
}
@@ -9,7 +9,7 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.AnActionEvent
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.scratch.ScratchFile
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
import org.jetbrains.kotlin.idea.scratch.getScratchFileFromSelectedEditor
class RunScratchFromHereAction : ScratchAction(
KotlinBundle.message("scratch.run.from.here.button"),
@@ -18,9 +18,9 @@ class RunScratchFromHereAction : ScratchAction(
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val scratchPanel = getScratchPanelFromSelectedEditor(project) ?: return
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
doAction(scratchPanel.scratchFile)
doAction(scratchFile)
}
companion object {
@@ -9,16 +9,16 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import org.jetbrains.kotlin.idea.scratch.getScratchPanel
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
import org.jetbrains.kotlin.idea.scratch.getScratchFile
import org.jetbrains.kotlin.idea.scratch.getScratchFileFromSelectedEditor
import javax.swing.Icon
abstract class ScratchAction(message: String, icon: Icon) : AnAction(message, message, icon) {
override fun update(e: AnActionEvent) {
val scratchPanel = e.getData(CommonDataKeys.EDITOR)
?.let { TextEditorProvider.getInstance().getTextEditor(it).getScratchPanel() }
?: e.project?.let { getScratchPanelFromSelectedEditor(it) }
val scratchFile = e.getData(CommonDataKeys.EDITOR)
?.let { TextEditorProvider.getInstance().getTextEditor(it).getScratchFile() }
?: e.project?.let { getScratchFileFromSelectedEditor(it) }
e.presentation.isVisible = scratchPanel != null
e.presentation.isVisible = scratchFile != null
}
}
@@ -17,10 +17,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.core.util.getLineCount
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
import org.jetbrains.kotlin.idea.scratch.ScratchExpression
import org.jetbrains.kotlin.idea.scratch.getScratchPanel
import org.jetbrains.kotlin.idea.scratch.isKotlinScratch
import org.jetbrains.kotlin.idea.scratch.isKotlinWorksheet
import org.jetbrains.kotlin.idea.scratch.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -72,9 +69,7 @@ class ScratchRunLineMarkerContributor : RunLineMarkerContributor() {
}
private fun getLastExecutedExpression(element: PsiElement): ScratchExpression? {
val panel = getSingleOpenedTextEditor(element.containingFile)?.getScratchPanel() ?: return null
val scratchFile = panel.scratchFile
val scratchFile = getSingleOpenedTextEditor(element.containingFile)?.getScratchFile() ?: return null
if (!scratchFile.options.isRepl) return null
val replExecutor = scratchFile.replScratchExecutor ?: return null
return replExecutor.getFirstNewExpression()
@@ -8,8 +8,7 @@ package org.jetbrains.kotlin.idea.scratch.actions
import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.AnActionEvent
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
import org.jetbrains.kotlin.idea.scratch.LOG as log
import org.jetbrains.kotlin.idea.scratch.getScratchFileFromSelectedEditor
class StopScratchAction : ScratchAction(
KotlinBundle.message("scratch.stop.button"),
@@ -24,8 +23,8 @@ class StopScratchAction : ScratchAction(
super.update(e)
val project = e.project ?: return
val panel = getScratchPanelFromSelectedEditor(project) ?: return
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
e.presentation.isEnabledAndVisible = ScratchCompilationSupport.isInProgress(panel.scratchFile)
e.presentation.isEnabledAndVisible = ScratchCompilationSupport.isInProgress(scratchFile)
}
}
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION
import org.jetbrains.kotlin.idea.scratch.ui.ScratchPanelListener
import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
@@ -32,31 +33,35 @@ val VirtualFile.isKotlinWorksheet: Boolean
val VirtualFile.isKotlinScratch: Boolean
get() = ScratchFileService.getInstance().getRootType(this) is ScratchRootType
fun getEditorWithoutScratchPanel(fileManager: FileEditorManager, virtualFile: VirtualFile): TextEditor? {
fun getEditorWithoutScratchFile(fileManager: FileEditorManager, virtualFile: VirtualFile): TextEditor? {
val editor = fileManager.getSelectedEditor(virtualFile) as? TextEditor
if (editor?.scratchTopPanel != null) return null
if (editor?.getScratchFile() != null) return null
return editor
}
fun getEditorWithScratchPanel(fileManager: FileEditorManager, virtualFile: VirtualFile): Pair<TextEditor, ScratchTopPanel>? {
@TestOnly
fun getScratchPanelFromEditorSelectedForFile(fileManager: FileEditorManager, virtualFile: VirtualFile): ScratchTopPanel? {
val editor = fileManager.getSelectedEditor(virtualFile) as? TextEditor ?: return null
val scratchTopPanel = editor.scratchTopPanel ?: return null
return editor to scratchTopPanel
return editor.scratchTopPanel
}
fun getAllEditorsWithScratchPanel(project: Project): List<Pair<TextEditor, ScratchTopPanel>> =
FileEditorManager.getInstance(project).allEditors.filterIsInstance<TextEditor>().mapNotNull {
val panel = it.scratchTopPanel
if (panel != null) it to panel else null
}
fun getScratchFileFromEditorSelectedForFile(fileManager: FileEditorManager, virtualFile: VirtualFile): ScratchFile? {
val editor = fileManager.getSelectedEditor(virtualFile) as? TextEditor ?: return null
return editor.getScratchFile()
}
fun getScratchPanelFromSelectedEditor(project: Project): ScratchTopPanel? {
fun getAllEditorsWithScratchFiles(project: Project): List<TextEditor> =
FileEditorManager.getInstance(project).allEditors
.filterIsInstance<TextEditor>()
.filter { it.getScratchFile() != null }
fun getScratchFileFromSelectedEditor(project: Project): ScratchFile? {
val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return null
return TextEditorProvider.getInstance().getTextEditor(editor).getScratchPanel()
return TextEditorProvider.getInstance().getTextEditor(editor).getScratchFile()
}
fun TextEditor.getScratchPanel(): ScratchTopPanel? {
return scratchTopPanel
fun TextEditor.getScratchFile(): ScratchFile? {
return scratchTopPanel?.scratchFile
}
fun TextEditor.addScratchPanel(panel: ScratchTopPanel) {
@@ -31,14 +31,14 @@ class ScratchFileHook(val project: Project) : ProjectComponent {
}
override fun projectClosed() {
getAllEditorsWithScratchPanel(project).forEach { (editor, _) -> editor.removeScratchPanel() }
getAllEditorsWithScratchFiles(project).forEach { editor -> editor.removeScratchPanel() }
}
private inner class ScratchEditorListener : FileEditorManagerListener {
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
if (!isPluggable(file)) return
val editor = getEditorWithoutScratchPanel(source, file) ?: return
val editor = getEditorWithoutScratchFile(source, file) ?: return
ScratchTopPanel.createPanel(project, file, editor)
@@ -176,10 +176,10 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
ScriptDependenciesManager.updateScriptDependenciesSynchronously(scratchFile, project)
val (_, scratchPanel) = getEditorWithScratchPanel(myManager, myFixture.file.virtualFile)
val scratchPanel= getScratchPanelFromEditorSelectedForFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
configureOptions(scratchPanel, text, myFixture.module)
configureOptions(scratchPanel.scratchFile, text, myFixture.module)
return scratchPanel
}
@@ -189,12 +189,12 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
ScriptDependenciesManager.updateScriptDependenciesSynchronously(worksheetFile, project)
val (_, scratchPanel) = getEditorWithScratchPanel(myManager, myFixture.file.virtualFile)
val scratchPanel = getScratchPanelFromEditorSelectedForFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
// We want to check that correct module is selected automatically,
// that's why we set `module` to null so it wouldn't be changed
configureOptions(scratchPanel, text, null)
configureOptions(scratchPanel.scratchFile, text, null)
return scratchPanel
}
@@ -234,9 +234,9 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
protected fun stopReplProcess() {
if (myFixture.file != null) {
val (_, scratchPanel) = getEditorWithScratchPanel(myManager, myFixture.file.virtualFile)
val scratchFile = getScratchFileFromEditorSelectedForFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
scratchPanel.scratchFile.replScratchExecutor?.stopAndWait()
scratchFile.replScratchExecutor?.stopAndWait()
}
UIUtil.dispatchAllInvocationEvents()
@@ -310,20 +310,20 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
}
fun configureOptions(
scratchPanel: ScratchTopPanel,
scratchFile: ScratchFile,
fileText: String,
module: Module?
) {
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// INTERACTIVE_MODE: ") != true) {
scratchPanel.setInteractiveMode(false)
scratchFile.saveOptions { copy(isInteractiveMode = false) }
}
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// REPL_MODE: ") == true) {
scratchPanel.setReplMode(true)
scratchFile.saveOptions { copy(isRepl = true) }
}
if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) {
scratchPanel.scratchFile.setModule(module)
scratchFile.setModule(module)
}
}
@@ -23,7 +23,7 @@ abstract class AbstractScratchLineMarkersTest : AbstractLineMarkersTest() {
fun doScratchTest(path: String) {
val fileText = FileUtil.loadFile(File(path))
val scratchFile = ScratchRootType.getInstance().createScratchFile(
val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile(
project,
"scratch.kts",
KotlinLanguage.INSTANCE,
@@ -31,14 +31,14 @@ abstract class AbstractScratchLineMarkersTest : AbstractLineMarkersTest() {
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file")
myFixture.openFileInEditor(scratchFile)
myFixture.openFileInEditor(scratchVirtualFile)
ScriptDependenciesManager.updateScriptDependenciesSynchronously(scratchFile, project)
ScriptDependenciesManager.updateScriptDependenciesSynchronously(scratchVirtualFile, project)
val (_, scratchPanel) = getEditorWithScratchPanel(FileEditorManager.getInstance(project), myFixture.file.virtualFile)
val scratchFile = getScratchFileFromEditorSelectedForFile(FileEditorManager.getInstance(project), myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
configureOptions(scratchPanel, fileText, null)
configureOptions(scratchFile, fileText, null)
val project = myFixture.project
val document = myFixture.editor.document
@@ -27,7 +27,7 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() {
myManager.closeFile(myFixture.file.virtualFile)
myManager.openFile(myFixture.file.virtualFile, true)
val (_, scratchPanelAfterClosingFile) = getEditorWithScratchPanel(myManager, myFixture.file.virtualFile) ?: error("Couldn't find scratch panel")
val scratchPanelAfterClosingFile = getScratchPanelFromEditorSelectedForFile(myManager, myFixture.file.virtualFile) ?: error("Couldn't find scratch panel")
Assert.assertEquals("Wrong value for isRepl checkbox", newIsReplValue, scratchPanelAfterClosingFile.scratchFile.options.isRepl)
Assert.assertEquals(
@@ -55,12 +55,12 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() {
}
fun testCurrentModuleIsAutomaticallySelectedForWorksheetFile() {
val scratchTopPanel = configureWorksheetByText("worksheet.ws.kts", testScratchText())
val scratchFile = configureWorksheetByText("worksheet.ws.kts", testScratchText()).scratchFile
Assert.assertEquals(
"Selected module should be equal to current project module for worksheets",
myFixture.module,
scratchTopPanel.scratchFile.module
scratchFile.module
)
}