mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[terminal console] WEB-75932 convert LF to CRLF correctly for processes without PTY
GitOrigin-RevId: 0bda77d5c4686ef70967fb35cbc2053849b3df9c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ad2307b5df
commit
38d2b04dfb
@@ -268,12 +268,12 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
myTerminalWidget.createTerminalSession(ttyConnector);
|
||||
myTerminalWidget.start();
|
||||
if (attachToProcessOutput) {
|
||||
boolean convertLfToCrlf = shouldConvertLfToCrlf(processHandler);
|
||||
boolean isProcessWithPty = isProcessWithPty(processHandler);
|
||||
if (processHandler instanceof ColoredProcessHandler coloredProcessHandler) {
|
||||
coloredProcessHandler.addRawTextListener(new ColoredProcessHandler.RawTextListener() {
|
||||
@Override
|
||||
public void onRawTextAvailable(@NotNull String text, @NotNull Key<?> outputType) {
|
||||
processProcessOutputText(text, outputType, convertLfToCrlf);
|
||||
processProcessOutputText(text, outputType, isProcessWithPty);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
processHandler.addProcessListener(new ProcessListener() {
|
||||
@Override
|
||||
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
|
||||
processProcessOutputText(event.getText(), outputType, convertLfToCrlf);
|
||||
processProcessOutputText(event.getText(), outputType, isProcessWithPty);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -297,7 +297,7 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
});
|
||||
}
|
||||
|
||||
private void processProcessOutputText(@NotNull String text, @NotNull Key<?> outputType, boolean convertLfToCrlf) {
|
||||
private void processProcessOutputText(@NotNull String text, @NotNull Key<?> outputType, boolean isProcessWithPty) {
|
||||
try {
|
||||
ConsoleViewContentType contentType = null;
|
||||
if (outputType != ProcessOutputTypes.STDOUT) {
|
||||
@@ -306,7 +306,7 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
if (outputType == ProcessOutputTypes.SYSTEM) {
|
||||
text = StringUtil.convertLineSeparators(text, LineSeparator.CRLF.getSeparatorString());
|
||||
}
|
||||
else if (convertLfToCrlf) {
|
||||
else if (!isProcessWithPty && myConvertLfToCrlfForNonPtyProcess) {
|
||||
text = convertTextToCRLF(text);
|
||||
}
|
||||
ConsoleViewContentType notNullContentType = ObjectUtils.notNull(contentType, ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
@@ -327,16 +327,13 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldConvertLfToCrlf(@NotNull ProcessHandler processHandler) {
|
||||
return myConvertLfToCrlfForNonPtyProcess && isNonPtyProcess(processHandler);
|
||||
}
|
||||
|
||||
private static boolean isNonPtyProcess(@NotNull ProcessHandler processHandler) {
|
||||
if (processHandler instanceof BaseProcessHandler) {
|
||||
Process process = ((BaseProcessHandler<?>)processHandler).getProcess();
|
||||
return !(process instanceof PtyProcess);
|
||||
private static boolean isProcessWithPty(@NotNull ProcessHandler processHandler) {
|
||||
if (processHandler instanceof BaseProcessHandler<?> baseProcessHandler) {
|
||||
Process process = baseProcessHandler.getProcess();
|
||||
return process instanceof PtyProcess ||
|
||||
(process instanceof PtyBasedProcess ptyBasedProcess && ptyBasedProcess.hasPty());
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -415,12 +412,7 @@ public class TerminalExecutionConsole implements ConsoleView, ObservableConsoleV
|
||||
}
|
||||
|
||||
public static boolean isAcceptable(@NotNull ProcessHandler processHandler) {
|
||||
if (processHandler instanceof BaseProcessHandler<?> baseProcessHandler) {
|
||||
Process process = baseProcessHandler.getProcess();
|
||||
return process instanceof PtyProcess ||
|
||||
(process instanceof PtyBasedProcess && ((PtyBasedProcess)process).hasPty());
|
||||
}
|
||||
return false;
|
||||
return isProcessWithPty(processHandler);
|
||||
}
|
||||
|
||||
private final class ConsoleTerminalWidget extends JBTerminalWidget {
|
||||
|
||||
+26
-3
@@ -54,14 +54,37 @@ class TerminalExecutionConsoleTest : BasePlatformTestCase() {
|
||||
return threadInfos.find { it.threadName.startsWith("TerminalEmulator-") }
|
||||
}
|
||||
|
||||
fun `test convert LF to CRLF for processes without PTY`(): Unit = timeoutRunBlocking(DEFAULT_TEST_TIMEOUT) {
|
||||
val processHandler = OSProcessHandler(MockPtyBasedProcess(false), "my command", Charsets.UTF_8)
|
||||
val console = withContext(Dispatchers.UI) {
|
||||
TerminalExecutionConsole(project, processHandler)
|
||||
}
|
||||
console.withConvertLfToCrlfForNonPtyProcess(true)
|
||||
TestProcessTerminationMessage.attach(processHandler)
|
||||
processHandler.startNotify()
|
||||
processHandler.notifyTextAvailable("Foo\nBar\nBaz", ProcessOutputTypes.STDOUT)
|
||||
processHandler.destroyProcess()
|
||||
console.awaitOutputContainsSubstring(substringToFind = TestProcessTerminationMessage.getMessage(MockPtyBasedProcess.EXIT_CODE))
|
||||
val output = TerminalOutput.collect(console.terminalWidget)
|
||||
output.assertLinesAre(listOf(
|
||||
"my command",
|
||||
"Foo",
|
||||
"Bar",
|
||||
"Baz",
|
||||
TestProcessTerminationMessage.getMessage(MockPtyBasedProcess.EXIT_CODE)
|
||||
))
|
||||
withContext(Dispatchers.UI) {
|
||||
Disposer.dispose(console)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test support ColoredProcessHandler`(): Unit = timeoutRunBlockingWithConsole { console ->
|
||||
val processHandler = ColoredProcessHandler(MockPtyBasedProcess(), "my command line", Charsets.UTF_8)
|
||||
val processHandler = ColoredProcessHandler(MockPtyBasedProcess(true), "my command line", Charsets.UTF_8)
|
||||
assertTrue(TerminalExecutionConsole.isAcceptable(processHandler))
|
||||
console.attachToProcess(processHandler)
|
||||
processHandler.startNotify()
|
||||
processHandler.notifyTextAvailable("\u001b[0m", ProcessOutputTypes.STDOUT)
|
||||
processHandler.notifyTextAvailable("\u001b[32mFoo\u001b[0m", ProcessOutputTypes.STDOUT)
|
||||
processHandler.setShouldDestroyProcessRecursively(false)
|
||||
TestProcessTerminationMessage.attach(processHandler)
|
||||
processHandler.destroyProcess()
|
||||
console.awaitOutputContainsSubstring(substringToFind = TestProcessTerminationMessage.getMessage(MockPtyBasedProcess.EXIT_CODE))
|
||||
@@ -75,7 +98,7 @@ class TerminalExecutionConsoleTest : BasePlatformTestCase() {
|
||||
}
|
||||
|
||||
fun `test support OSProcessHandler`(): Unit = timeoutRunBlockingWithConsole { console ->
|
||||
val processHandler = OSProcessHandler(MockPtyBasedProcess(), "command line", Charsets.UTF_8)
|
||||
val processHandler = OSProcessHandler(MockPtyBasedProcess(true), "command line", Charsets.UTF_8)
|
||||
assertTrue(TerminalExecutionConsole.isAcceptable(processHandler))
|
||||
console.attachToProcess(processHandler)
|
||||
processHandler.startNotify()
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.execution.process.KillableProcessHandler
|
||||
import com.intellij.execution.process.ProcessHandler
|
||||
import com.intellij.execution.process.ProcessTerminatedListener
|
||||
import com.intellij.execution.process.PtyBasedProcess
|
||||
import com.intellij.execution.process.SelfKiller
|
||||
import com.intellij.platform.eel.EelExecApi.Pty
|
||||
import com.intellij.platform.eel.ExecuteProcessException
|
||||
import com.intellij.util.io.BaseDataReader
|
||||
@@ -43,7 +44,7 @@ internal fun ProcessHandler.writeToStdinAndHitEnter(input: String) {
|
||||
}
|
||||
}
|
||||
|
||||
internal class MockPtyBasedProcess : Process(), PtyBasedProcess {
|
||||
internal class MockPtyBasedProcess(private val withPty: Boolean) : Process(), PtyBasedProcess, SelfKiller {
|
||||
|
||||
private val exitCodeFuture: CompletableFuture<Int> = CompletableFuture()
|
||||
|
||||
@@ -61,7 +62,7 @@ internal class MockPtyBasedProcess : Process(), PtyBasedProcess {
|
||||
override fun getErrorStream(): InputStream = InputStream.nullInputStream()
|
||||
override fun getInputStream(): InputStream = InputStream.nullInputStream()
|
||||
|
||||
override fun hasPty(): Boolean = true
|
||||
override fun hasPty(): Boolean = withPty
|
||||
|
||||
override fun setWindowSize(columns: Int, rows: Int) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user