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.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 maxInsertOffset = 60
|
||||
private val minSpaceCount = 4
|
||||
|
||||
private val toolwindowHandler = getToolwindowHandler(textEditor)
|
||||
|
||||
override fun onStart(file: ScratchFile) {
|
||||
toolwindowHandler.onStart(file)
|
||||
toolWindowHandler.onStart(file)
|
||||
}
|
||||
|
||||
override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
|
||||
@@ -40,21 +41,21 @@ class InlayScratchOutputHandler(private val textEditor: TextEditor) : ScratchOut
|
||||
createInlay(file, expression, output)
|
||||
|
||||
if (output.type == ScratchOutputType.ERROR) {
|
||||
toolwindowHandler.handle(file, expression, output)
|
||||
toolWindowHandler.handle(file, expression, output)
|
||||
}
|
||||
}
|
||||
|
||||
override fun error(file: ScratchFile, message: String) {
|
||||
toolwindowHandler.error(file, message)
|
||||
toolWindowHandler.error(file, message)
|
||||
}
|
||||
|
||||
override fun onFinish(file: ScratchFile) {
|
||||
toolwindowHandler.onFinish(file)
|
||||
toolWindowHandler.onFinish(file)
|
||||
}
|
||||
|
||||
override fun clear(file: ScratchFile) {
|
||||
clearInlays(textEditor)
|
||||
toolwindowHandler.clear(file)
|
||||
toolWindowHandler.clear(file)
|
||||
}
|
||||
|
||||
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) {
|
||||
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.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) {
|
||||
TestOutputHandler
|
||||
} 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 {
|
||||
val project = file.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)
|
||||
ScratchToolWindowFactory().createToolWindowContent(project, window)
|
||||
|
||||
Disposer.register(parentDisposable, Disposable {
|
||||
window.setAvailable(false, null)
|
||||
toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
|
||||
})
|
||||
|
||||
return window
|
||||
|
||||
+4
-3
@@ -25,8 +25,7 @@ import com.intellij.pom.Navigatable
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.scratch.*
|
||||
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchOutputHandler
|
||||
import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter
|
||||
import org.jetbrains.kotlin.idea.scratch.output.*
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
|
||||
private const val KTS_SCRATCH_EDITOR_PROVIDER: String = "KtsScratchFileEditorProvider"
|
||||
@@ -56,7 +55,8 @@ class KtScratchFileEditorWithPreview private constructor(
|
||||
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)
|
||||
|
||||
init {
|
||||
@@ -71,6 +71,7 @@ class KtScratchFileEditorWithPreview private constructor(
|
||||
override fun dispose() {
|
||||
scratchFile.replScratchExecutor?.stop()
|
||||
scratchFile.compilingScratchExecutor?.stop()
|
||||
releaseToolWindowHandler(toolWindowHandler)
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user