KT-32366: Inject toolWindowHandler from InlayScratchOutputHandler
- `toolWindowHandler` would be shared between different scratch editors, so we need `ScratchToolWindowHandlerKeeper` to provide proper mechanism for its acquiring and releasing - fix problem when scratch output panel is never released after first scratch opening by properly unregistering `toolWindow` with `ToolWindowManager`
This commit is contained in:
committed by
Roman Golyshev
parent
d0cd4967a7
commit
e321ee1396
+10
-9
@@ -23,15 +23,16 @@ import com.intellij.openapi.util.text.StringUtil
|
|||||||
import org.jetbrains.kotlin.idea.scratch.ScratchExpression
|
import org.jetbrains.kotlin.idea.scratch.ScratchExpression
|
||||||
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
||||||
|
|
||||||
class InlayScratchOutputHandler(private val textEditor: TextEditor) : ScratchOutputHandler {
|
class InlayScratchOutputHandler(
|
||||||
|
private val textEditor: TextEditor,
|
||||||
|
private val toolWindowHandler: ScratchOutputHandler
|
||||||
|
) : ScratchOutputHandler {
|
||||||
private val maxLineLength = 120
|
private val maxLineLength = 120
|
||||||
private val maxInsertOffset = 60
|
private val maxInsertOffset = 60
|
||||||
private val minSpaceCount = 4
|
private val minSpaceCount = 4
|
||||||
|
|
||||||
private val toolwindowHandler = getToolwindowHandler(textEditor)
|
|
||||||
|
|
||||||
override fun onStart(file: ScratchFile) {
|
override fun onStart(file: ScratchFile) {
|
||||||
toolwindowHandler.onStart(file)
|
toolWindowHandler.onStart(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
||||||
@@ -40,21 +41,21 @@ class InlayScratchOutputHandler(private val textEditor: TextEditor) : ScratchOut
|
|||||||
createInlay(file, expression, output)
|
createInlay(file, expression, output)
|
||||||
|
|
||||||
if (output.type == ScratchOutputType.ERROR) {
|
if (output.type == ScratchOutputType.ERROR) {
|
||||||
toolwindowHandler.handle(file, expression, output)
|
toolWindowHandler.handle(file, expression, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun error(file: ScratchFile, message: String) {
|
override fun error(file: ScratchFile, message: String) {
|
||||||
toolwindowHandler.error(file, message)
|
toolWindowHandler.error(file, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish(file: ScratchFile) {
|
override fun onFinish(file: ScratchFile) {
|
||||||
toolwindowHandler.onFinish(file)
|
toolWindowHandler.onFinish(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear(file: ScratchFile) {
|
override fun clear(file: ScratchFile) {
|
||||||
clearInlays(textEditor)
|
clearInlays(textEditor)
|
||||||
toolwindowHandler.clear(file)
|
toolWindowHandler.clear(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createInlay(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
private fun createInlay(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
||||||
@@ -96,7 +97,7 @@ class InlayScratchOutputHandler(private val textEditor: TextEditor) : ScratchOut
|
|||||||
|
|
||||||
private fun printToToolWindow(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
private fun printToToolWindow(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
||||||
if (output.type != ScratchOutputType.ERROR) {
|
if (output.type != ScratchOutputType.ERROR) {
|
||||||
toolwindowHandler.handle(file, expression, output)
|
toolWindowHandler.handle(file, expression, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+61
-5
@@ -37,12 +37,68 @@ import org.jetbrains.kotlin.idea.scratch.ScratchExpression
|
|||||||
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
|
||||||
|
/**
|
||||||
fun getToolwindowHandler(parentDisposable: Disposable): ScratchOutputHandler {
|
* Method to retrieve shared instance of scratches ToolWindow output handler.
|
||||||
|
*
|
||||||
|
* [releaseToolWindowHandler] must be called for every output handler received from this method.
|
||||||
|
*
|
||||||
|
* Can be called from EDT only.
|
||||||
|
*
|
||||||
|
* @return new toolWindow output handler if one does not exist, otherwise returns the existing one. When application in test mode,
|
||||||
|
* returns [TestOutputHandler].
|
||||||
|
*/
|
||||||
|
fun requestToolWindowHandler(): ScratchOutputHandler {
|
||||||
return if (ApplicationManager.getApplication().isUnitTestMode) {
|
return if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
TestOutputHandler
|
TestOutputHandler
|
||||||
} else {
|
} else {
|
||||||
ToolWindowScratchOutputHandler(parentDisposable)
|
ScratchToolWindowHandlerKeeper.requestOutputHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called once with the output handler received from the [requestToolWindowHandler] call.
|
||||||
|
*
|
||||||
|
* When release is called for every request, the output handler is actually disposed.
|
||||||
|
*
|
||||||
|
* When application in test mode, does nothing.
|
||||||
|
*
|
||||||
|
* Can be called from EDT only.
|
||||||
|
*/
|
||||||
|
fun releaseToolWindowHandler(scratchOutputHandler: ScratchOutputHandler) {
|
||||||
|
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
|
ScratchToolWindowHandlerKeeper.releaseOutputHandler(scratchOutputHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements logic of shared pointer for the toolWindow output handler.
|
||||||
|
*
|
||||||
|
* Not thread safe! Can be used only from the EDT.
|
||||||
|
*/
|
||||||
|
private object ScratchToolWindowHandlerKeeper {
|
||||||
|
private var toolWindowHandler: ScratchOutputHandler? = null
|
||||||
|
private var toolWindowDisposable = Disposer.newDisposable()
|
||||||
|
private var counter = 0
|
||||||
|
|
||||||
|
fun requestOutputHandler(): ScratchOutputHandler {
|
||||||
|
if (counter == 0) {
|
||||||
|
toolWindowHandler = ToolWindowScratchOutputHandler(toolWindowDisposable)
|
||||||
|
}
|
||||||
|
|
||||||
|
counter += 1
|
||||||
|
return toolWindowHandler!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseOutputHandler(scratchOutputHandler: ScratchOutputHandler) {
|
||||||
|
require(counter > 0) { "Counter is $counter, nothing to release!" }
|
||||||
|
require(toolWindowHandler === scratchOutputHandler) { "$scratchOutputHandler differs from stored $toolWindowHandler" }
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
if (counter == 0) {
|
||||||
|
Disposer.dispose(toolWindowDisposable)
|
||||||
|
toolWindowDisposable = Disposer.newDisposable()
|
||||||
|
toolWindowHandler = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,12 +186,12 @@ private class ToolWindowScratchOutputHandler(private val parentDisposable: Dispo
|
|||||||
private fun createToolWindow(file: ScratchFile): ToolWindow {
|
private fun createToolWindow(file: ScratchFile): ToolWindow {
|
||||||
val project = file.project
|
val project = file.project
|
||||||
val toolWindowManager = ToolWindowManager.getInstance(project)
|
val toolWindowManager = ToolWindowManager.getInstance(project)
|
||||||
toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, false, 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(parentDisposable, Disposable {
|
Disposer.register(parentDisposable, Disposable {
|
||||||
window.setAvailable(false, null)
|
toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
return window
|
return window
|
||||||
|
|||||||
+4
-3
@@ -25,8 +25,7 @@ import com.intellij.pom.Navigatable
|
|||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.idea.scratch.*
|
import org.jetbrains.kotlin.idea.scratch.*
|
||||||
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchOutputHandler
|
import org.jetbrains.kotlin.idea.scratch.output.*
|
||||||
import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter
|
|
||||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||||
|
|
||||||
private const val KTS_SCRATCH_EDITOR_PROVIDER: String = "KtsScratchFileEditorProvider"
|
private const val KTS_SCRATCH_EDITOR_PROVIDER: String = "KtsScratchFileEditorProvider"
|
||||||
@@ -56,7 +55,8 @@ class KtScratchFileEditorWithPreview private constructor(
|
|||||||
preview: TextEditor
|
preview: TextEditor
|
||||||
) : TextEditorWithPreview(editor, preview), TextEditor {
|
) : TextEditorWithPreview(editor, preview), TextEditor {
|
||||||
|
|
||||||
private val inlayOutputHandler = InlayScratchOutputHandler(editor)
|
private val toolWindowHandler: ScratchOutputHandler = requestToolWindowHandler()
|
||||||
|
private val inlayOutputHandler = InlayScratchOutputHandler(editor, toolWindowHandler)
|
||||||
private val scratchTopPanel = ScratchTopPanel(scratchFile)
|
private val scratchTopPanel = ScratchTopPanel(scratchFile)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -71,6 +71,7 @@ class KtScratchFileEditorWithPreview private constructor(
|
|||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
scratchFile.replScratchExecutor?.stop()
|
scratchFile.replScratchExecutor?.stop()
|
||||||
scratchFile.compilingScratchExecutor?.stop()
|
scratchFile.compilingScratchExecutor?.stop()
|
||||||
|
releaseToolWindowHandler(toolWindowHandler)
|
||||||
super.dispose()
|
super.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user