mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[pycharm] PY-86511 Prevent exit tag from being copied when tags are disabled
[pycharm] PY-86511 Refactor output tag logic [pycharm] PY-86511 Prevent exit tag from being copied when tags are disabled Merge-request: IJ-MR-195636 Merged-by: David Lysenko <david.lysenko@jetbrains.com> (cherry picked from commit 22cf8cc64f95de4270257342f7624f0227e2c1c2) IJ-MR-195636 GitOrigin-RevId: 30cd806c72b530dfea362121b7dc90ff3262fa5a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
43a819262a
commit
74df445149
@@ -34,6 +34,7 @@ import com.intellij.python.processOutput.frontend.ui.components.OutputSectionTes
|
||||
import com.intellij.python.processOutput.frontend.ui.components.TreeSectionTestTags
|
||||
import com.intellij.python.processOutput.frontend.ui.shortenedCommandString
|
||||
import java.util.WeakHashMap
|
||||
import kotlin.enums.enumEntries
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Instant
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
@@ -284,6 +285,8 @@ internal class ProcessOutputControllerService(
|
||||
val showTags = processOutputUiState.filters.active.contains(OutputFilter.Item.SHOW_TAGS)
|
||||
|
||||
val stringToCopy = buildString {
|
||||
var lastTag: Tag? = null
|
||||
|
||||
loggedProcess.lines.forEach { line ->
|
||||
if (showTags) {
|
||||
val tag = when (line.kind) {
|
||||
@@ -291,11 +294,13 @@ internal class ProcessOutputControllerService(
|
||||
OutputKindDto.ERR -> Tag.ERROR
|
||||
}
|
||||
|
||||
append("[$tag] ".padStart(Tag.maxLength + 3))
|
||||
} else {
|
||||
repeat(Tag.maxLength + 3) {
|
||||
append(' ')
|
||||
if (lastTag == tag) {
|
||||
append(Tag.blankBracketTagString)
|
||||
} else {
|
||||
append(tag.bracketTagString)
|
||||
}
|
||||
|
||||
lastTag = tag
|
||||
}
|
||||
|
||||
appendLine(line.text)
|
||||
@@ -307,7 +312,10 @@ internal class ProcessOutputControllerService(
|
||||
}
|
||||
|
||||
exitData?.also { exitData ->
|
||||
append("[${Tag.EXIT}] ".padStart(Tag.maxLength + 3))
|
||||
if (showTags) {
|
||||
append(Tag.EXIT.bracketTagString)
|
||||
}
|
||||
|
||||
append(exitData.exitCode)
|
||||
|
||||
exitData.additionalMessageToUser?.also { message ->
|
||||
@@ -736,15 +744,27 @@ internal class ProcessOutputControllerService(
|
||||
}
|
||||
}
|
||||
|
||||
internal object Tag {
|
||||
val ERROR = message("process.output.output.tag.stdout")
|
||||
val OUTPUT = message("process.output.output.tag.stderr")
|
||||
val EXIT = message("process.output.output.tag.exit")
|
||||
internal enum class Tag(val text: String) {
|
||||
ERROR(message("process.output.output.tag.stderr")),
|
||||
OUTPUT(message("process.output.output.tag.stdout")),
|
||||
EXIT(message("process.output.output.tag.exit"));
|
||||
|
||||
val maxLength: Int =
|
||||
Tag::class.java.declaredFields
|
||||
.filter { it.type == String::class.java }
|
||||
.fastMaxOfOrDefault(0) { (it.get(null) as String).length }
|
||||
override fun toString(): String = text
|
||||
|
||||
val bracketTagString: String
|
||||
get() = "[$text] ".padStart(bracketPadding)
|
||||
|
||||
val colonTagString: String
|
||||
get() = "$text:".padStart(colonPadding)
|
||||
|
||||
companion object {
|
||||
private val maxLength = enumEntries<Tag>().fastMaxOfOrDefault(0) { it.text.length }
|
||||
private val bracketPadding = maxLength + 3 // opening bracket, closing bracket, and space
|
||||
private val colonPadding = maxLength + 1 // colon
|
||||
|
||||
val blankBracketTagString: String = " ".repeat(bracketPadding)
|
||||
val blankColonTagString: String = " ".repeat(colonPadding)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> boundedLinkedHashMap(maxSize: Int): LinkedHashMap<K, V> =
|
||||
|
||||
@@ -260,15 +260,8 @@ private fun OutputLine(
|
||||
) {
|
||||
if (displayTags) {
|
||||
DisableSelection {
|
||||
val padding = Tag.maxLength + 1
|
||||
|
||||
Text(
|
||||
text =
|
||||
if (sectionIndicator != null) {
|
||||
"${sectionIndicator.tag}:".padStart(padding, ' ')
|
||||
} else {
|
||||
" ".repeat(padding)
|
||||
},
|
||||
text = sectionIndicator?.tag?.colonTagString ?: Tag.blankColonTagString,
|
||||
style = JewelTheme.consoleTextStyle,
|
||||
fontWeight = FontWeight.Thin,
|
||||
modifier =
|
||||
@@ -309,7 +302,7 @@ private fun OutputLine(
|
||||
}
|
||||
|
||||
private data class SectionIndicator(
|
||||
val tag: String,
|
||||
val tag: Tag,
|
||||
val copyButtonTestTag: String = OutputSectionTestTags.COPY_OUTPUT_TAG_SECTION_BUTTON,
|
||||
val onCopy: () -> Unit,
|
||||
)
|
||||
@@ -430,8 +423,8 @@ private sealed class InfoLine {
|
||||
private val OutputKindDto.tag
|
||||
get() =
|
||||
when (this) {
|
||||
OutputKindDto.OUT -> Tag.ERROR
|
||||
OutputKindDto.ERR -> Tag.OUTPUT
|
||||
OutputKindDto.OUT -> Tag.OUTPUT
|
||||
OutputKindDto.ERR -> Tag.ERROR
|
||||
}
|
||||
|
||||
internal object OutputSectionTestTags {
|
||||
|
||||
Vendored
+103
@@ -7,15 +7,18 @@ import com.intellij.python.community.execService.Args
|
||||
import com.intellij.python.community.execService.BinOnEel
|
||||
import com.intellij.python.community.execService.ExecService
|
||||
import com.intellij.python.community.execService.impl.LoggingLimits
|
||||
import com.intellij.python.community.execService.impl.LoggingProcess
|
||||
import com.intellij.python.junit5Tests.framework.env.PyEnvTestCase
|
||||
import com.intellij.python.junit5Tests.framework.env.PythonBinaryPath
|
||||
import com.intellij.python.processOutput.common.OutputKindDto
|
||||
import com.intellij.python.processOutput.common.OutputLineDto
|
||||
import com.intellij.python.processOutput.frontend.CoroutineNames
|
||||
import com.intellij.python.processOutput.frontend.LoggedProcess
|
||||
import com.intellij.python.processOutput.frontend.OutputFilter
|
||||
import com.intellij.python.processOutput.frontend.ProcessOutputControllerService
|
||||
import com.intellij.python.processOutput.frontend.ProcessOutputControllerServiceLimits
|
||||
import com.intellij.python.processOutput.frontend.ProcessStatus
|
||||
import com.intellij.python.processOutput.frontend.ui.toggle
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.common.waitUntil
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
@@ -374,6 +377,106 @@ class ProcessOutputControllerServiceTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toolbar copy includes tags depending on whether the filter is enabled`(
|
||||
@TempDir cwd: Path,
|
||||
@PythonBinaryPath python: PythonBinary,
|
||||
): Unit = timeoutRunBlocking {
|
||||
val service = projectFixture.get().service<ProcessOutputControllerService>()
|
||||
|
||||
val binOnEel = BinOnEel(python, cwd)
|
||||
val mainPy = Files.createFile(cwd.resolve(MAIN_PY))
|
||||
|
||||
edtWriteAction {
|
||||
mainPy.toFile().writeText(
|
||||
"""
|
||||
import sys
|
||||
|
||||
print("out1")
|
||||
print("out2")
|
||||
print("out3")
|
||||
print("out4")
|
||||
print("out5")
|
||||
print("out6")
|
||||
|
||||
print("err7", file=sys.stderr)
|
||||
print("err8", file=sys.stderr)
|
||||
print("err9", file=sys.stderr)
|
||||
print("err10", file=sys.stderr)
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
val loggingProcess = withContext(NON_INTERACTIVE_ROOT_TRACE_CONTEXT) {
|
||||
ExecService().executeGetProcess(
|
||||
binOnEel,
|
||||
Args(MAIN_PY),
|
||||
CoroutineScope(coroutineContext),
|
||||
).getOrThrow()
|
||||
}
|
||||
|
||||
// reading all stdout
|
||||
loggingProcess.inputStream.readAllBytes()
|
||||
|
||||
waitUntil {
|
||||
service.loggedProcesses.value.lastOrNull()?.lines?.size == 6
|
||||
}
|
||||
|
||||
val process = service.loggedProcesses.value.last()
|
||||
|
||||
// reading all stderr
|
||||
loggingProcess.errorStream.readAllBytes()
|
||||
|
||||
waitUntil {
|
||||
service.loggedProcesses.value.lastOrNull()?.lines?.size == 10
|
||||
}
|
||||
|
||||
// copying output
|
||||
service.copyOutputToClipboard(process)
|
||||
|
||||
// copied output should include tags
|
||||
assertEquals(
|
||||
"""
|
||||
[stdout] out1
|
||||
out2
|
||||
out3
|
||||
out4
|
||||
out5
|
||||
out6
|
||||
[stderr] err7
|
||||
err8
|
||||
err9
|
||||
err10
|
||||
[exit] 0
|
||||
|
||||
""".trimIndent(),
|
||||
CopyPasteManager.getInstance().getContents<String>(DataFlavor.stringFlavor),
|
||||
)
|
||||
|
||||
// toggling the show tags filter
|
||||
service.processOutputUiState.filters.active.toggle(OutputFilter.Item.SHOW_TAGS)
|
||||
service.copyOutputToClipboard(process)
|
||||
|
||||
// copied output should not include tags
|
||||
waitUntil("output without tags") {
|
||||
CopyPasteManager.getInstance().getContents<String>(DataFlavor.stringFlavor) ==
|
||||
"""
|
||||
out1
|
||||
out2
|
||||
out3
|
||||
out4
|
||||
out5
|
||||
out6
|
||||
err7
|
||||
err8
|
||||
err9
|
||||
err10
|
||||
0
|
||||
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `non-ascii output lines are reflected properly`(
|
||||
@TempDir cwd: Path,
|
||||
|
||||
Reference in New Issue
Block a user