1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.execution.impl;
4 import com.google.common.base.Ascii;
5 import com.intellij.execution.ExecutionBundle;
6 import com.intellij.execution.process.*;
7 import com.intellij.execution.ui.ConsoleViewContentType;
8 import com.intellij.openapi.util.Key;
9 import com.intellij.openapi.util.SystemInfo;
10 import com.intellij.openapi.vfs.encoding.EncodingManager;
11 import com.pty4j.PtyProcess;
12 import org.jetbrains.annotations.NotNull;
13 import org.jetbrains.annotations.Nullable;
14 import org.jetbrains.annotations.TestOnly;
16 import java.io.IOException;
17 import java.io.OutputStream;
18 import java.io.OutputStreamWriter;
19 import java.io.Writer;
20 import java.nio.charset.Charset;
22 public class ConsoleViewRunningState extends ConsoleState {
23 private final ConsoleViewImpl myConsole;
24 private final ProcessHandler myProcessHandler;
25 private final ConsoleState myFinishedStated;
26 private final Writer myUserInputWriter;
27 private final ProcessStreamsSynchronizer myStreamsSynchronizer;
29 private final ProcessAdapter myProcessListener = new ProcessAdapter() {
31 public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
32 if (outputType instanceof ProcessOutputType) {
33 myStreamsSynchronizer.doWhenStreamsSynchronized(event.getText(), (ProcessOutputType)outputType, () -> {
34 print(event.getText(), outputType);
38 print(event.getText(), outputType);
43 public ConsoleViewRunningState(@NotNull ConsoleViewImpl console,
44 @NotNull ProcessHandler processHandler,
45 @NotNull ConsoleState finishedStated,
46 boolean attachToStdOut,
47 boolean attachToStdIn) {
49 myProcessHandler = processHandler;
50 myFinishedStated = finishedStated;
51 myStreamsSynchronizer = attachToStdOut ? new ProcessStreamsSynchronizer(console) : null;
53 // attach to process stdout
55 processHandler.addProcessListener(myProcessListener);
58 // attach to process stdin
60 final OutputStream processInput = myProcessHandler.getProcessInput();
61 myUserInputWriter = processInput == null ? null : createOutputStreamWriter(processInput, processHandler);
64 myUserInputWriter = null;
68 private static OutputStreamWriter createOutputStreamWriter(OutputStream processInput, ProcessHandler processHandler) {
69 Charset charset = null;
70 if (processHandler instanceof OSProcessHandler) {
71 charset = ((OSProcessHandler)processHandler).getCharset();
73 if (charset == null) {
74 charset = EncodingManager.getInstance().getDefaultCharset();
76 return new OutputStreamWriter(processInput, charset);
79 private void print(@NotNull String text, @NotNull Key<?> outputType) {
80 myConsole.print(text, ConsoleViewContentType.getConsoleViewType(outputType));
85 public ConsoleState dispose() {
86 if (myProcessHandler != null) {
87 myProcessHandler.removeProcessListener(myProcessListener);
89 return myFinishedStated;
93 public boolean isCommandLine(@NotNull String line) {
94 return myProcessHandler instanceof BaseProcessHandler && line.equals(((BaseProcessHandler)myProcessHandler).getCommandLine());
98 public boolean isFinished() {
99 return myProcessHandler == null || myProcessHandler.isProcessTerminated();
103 public boolean isRunning() {
104 return myProcessHandler != null && !myProcessHandler.isProcessTerminated();
108 public void sendUserInput(@NotNull final String input) throws IOException {
109 if (myUserInputWriter == null) {
110 throw new IOException(ExecutionBundle.message("no.user.process.input.error.message"));
112 char enterKeyCode = getEnterKeyCode();
113 String inputToSend = input.replace((char)Ascii.LF, enterKeyCode);
114 myUserInputWriter.write(inputToSend);
115 myUserInputWriter.flush();
118 private char getEnterKeyCode() {
119 if (SystemInfo.isWindows &&
120 myProcessHandler instanceof OSProcessHandler &&
121 ((OSProcessHandler)myProcessHandler).getProcess() instanceof PtyProcess) {
122 // pty4j expects \r as Enter key code
123 // https://github.com/JetBrains/pty4j/blob/0.9.4/test/com/pty4j/PtyTest.java#L54
131 public ConsoleState attachTo(@NotNull final ConsoleViewImpl console, final @NotNull ProcessHandler processHandler) {
132 return dispose().attachTo(console, processHandler);
137 ProcessStreamsSynchronizer getStreamsSynchronizer() {
138 return myStreamsSynchronizer;
142 public String toString() {
143 return "Running state";