mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
PY-85090
[pycharm] PY-85090 Improve close detection for LoggingProcess [pycharm] PY-85090 Address feedback [pycharm] PY-85090 Add empty screen when contexts are selected [pycharm] PY-85090 Change expand/collapse all logic [pycharm] PY-85090 Improve collapse all/expand all logic [pycharm] PY-85090 Add bulk read override Merge-request: IJ-MR-179958 Merged-by: David Lysenko <david.lysenko@jetbrains.com> GitOrigin-RevId: 00b7b0dd121eeebcb5920514ca8a535520f71160
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6287d2f876
commit
72f575fa9b
@@ -7,6 +7,7 @@ import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.util.io.awaitExit
|
||||
import com.intellij.util.io.readLineAsync
|
||||
import com.intellij.util.io.toByteArray
|
||||
import com.jetbrains.python.TraceContext
|
||||
import com.jetbrains.python.errorProcessing.Exe
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -24,7 +25,9 @@ import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
@@ -196,24 +199,17 @@ private class LoggingInputStream(
|
||||
) : InputStream() {
|
||||
private val bytes = ByteStreams.newDataOutput()
|
||||
private var tail = 0
|
||||
private var closed = AtomicBoolean(false)
|
||||
|
||||
val byteArray
|
||||
get() = bytes.toByteArray()
|
||||
|
||||
override fun read(): Int {
|
||||
val byte = try {
|
||||
backingInputStream.read()
|
||||
if (closed.get()) {
|
||||
return -1
|
||||
}
|
||||
catch (e: IOException) {
|
||||
// ugly hack; but the Process' `.destroy` methods abruptly close
|
||||
// the stream, making all pending readers throw an exception.
|
||||
// we can handle this case as legal here
|
||||
if (e.message == "Stream closed") {
|
||||
return -1
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
val byte = backingInputStream.read()
|
||||
|
||||
if (tail < LoggingLimits.MAX_OUTPUT_SIZE && byte != -1) {
|
||||
bytes.write(byte)
|
||||
@@ -222,6 +218,39 @@ private class LoggingInputStream(
|
||||
|
||||
return byte
|
||||
}
|
||||
|
||||
/**
|
||||
* Chunked read. The read bytes are also logged into the corresponding byte stream. If limit of [LoggingLimits.MAX_OUTPUT_SIZE] is
|
||||
* reached, then the logged bytes are truncated.
|
||||
*/
|
||||
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
if (closed.get()) {
|
||||
return -1
|
||||
}
|
||||
|
||||
val finalLen = backingInputStream.read(b, off, len)
|
||||
|
||||
if (finalLen != -1) {
|
||||
val truncatedLen = if (tail + finalLen > LoggingLimits.MAX_OUTPUT_SIZE) {
|
||||
LoggingLimits.MAX_OUTPUT_SIZE - tail
|
||||
}
|
||||
else {
|
||||
finalLen
|
||||
}
|
||||
|
||||
if (truncatedLen > 0) {
|
||||
bytes.write(b, off, truncatedLen)
|
||||
tail += truncatedLen
|
||||
}
|
||||
}
|
||||
|
||||
return finalLen
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
closed.set(true)
|
||||
super.close()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun collectOutputLines(
|
||||
|
||||
@@ -57,7 +57,7 @@ internal interface ProcessOutputController {
|
||||
|
||||
fun collapseAllContexts()
|
||||
fun expandAllContexts()
|
||||
fun selectProcess(process: LoggedProcess)
|
||||
fun selectProcess(process: LoggedProcess?)
|
||||
fun toggleTreeFilter(filter: TreeFilter)
|
||||
fun toggleOutputFilter(filter: OutputFilter)
|
||||
fun toggleProcessInfo()
|
||||
@@ -185,26 +185,27 @@ class ProcessOutputControllerService(
|
||||
}
|
||||
|
||||
override fun collapseAllContexts() {
|
||||
processTreeUiState.treeState.openNodes.forEach {
|
||||
processTreeUiState.treeState.toggleNode(it)
|
||||
}
|
||||
processTreeUiState.treeState.openNodes = setOf()
|
||||
|
||||
ProcessOutputUsageCollector.treeCollapseAllClicked()
|
||||
}
|
||||
|
||||
override fun expandAllContexts() {
|
||||
loggedProcesses.value
|
||||
.mapNotNull { it.traceContext }
|
||||
.toSet()
|
||||
.subtract(processTreeUiState.treeState.openNodes)
|
||||
.forEach {
|
||||
processTreeUiState.treeState.toggleNode(it)
|
||||
}
|
||||
processTreeUiState.treeState.openNodes =
|
||||
processTreeUiState.tree.value
|
||||
.walkDepthFirst()
|
||||
.mapNotNull {
|
||||
when (val data = it.data) {
|
||||
is TreeNode.Context -> data.traceContext
|
||||
is TreeNode.Process -> null
|
||||
}
|
||||
}
|
||||
.toSet()
|
||||
|
||||
ProcessOutputUsageCollector.treeExpandAllClicked()
|
||||
}
|
||||
|
||||
override fun selectProcess(process: LoggedProcess) {
|
||||
override fun selectProcess(process: LoggedProcess?) {
|
||||
selectedProcess.value = process
|
||||
ProcessOutputUsageCollector.treeProcessSelected()
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ internal fun TreeSection(controller: ProcessOutputController) {
|
||||
|
||||
if (node is TreeNode.Process) {
|
||||
controller.selectProcess(node.process)
|
||||
} else {
|
||||
controller.selectProcess(null)
|
||||
}
|
||||
},
|
||||
style = LazyTreeStyle(
|
||||
|
||||
@@ -78,7 +78,7 @@ internal abstract class ProcessOutputTest {
|
||||
controllerSpy.expandAllContexts()
|
||||
}
|
||||
|
||||
override fun selectProcess(process: LoggedProcess) {
|
||||
override fun selectProcess(process: LoggedProcess?) {
|
||||
controllerSpy.selectProcess(process)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user