package com.atsebak.embeddedlinuxjvm.console;
import com.google.common.io.Closeables;
import com.intellij.execution.ui.ConsoleViewContentType;
import lombok.AllArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import static com.intellij.execution.ui.ConsoleViewContentType.ERROR_OUTPUT;
import static com.intellij.execution.ui.ConsoleViewContentType.NORMAL_OUTPUT;
public class EmbeddedLinuxJVMOutputForwarder {
private static final int SIZE = 2048;
@NotNull
private final ByteArrayOutputStream myStdErr;
@NotNull
private final ByteArrayOutputStream myOutput;
@NotNull
private final EmbeddedLinuxJVMConsoleView myConsoleView;
private ConsoleViewContentType myPreviousContentType;
/**
* Constructor
*
* @param consoleView
*/
public EmbeddedLinuxJVMOutputForwarder(@NotNull EmbeddedLinuxJVMConsoleView consoleView) {
myConsoleView = consoleView;
myStdErr = new ByteArrayOutputStream(SIZE);
myOutput = new ByteArrayOutputStream(SIZE * 2);
}
/**
* Start listening
* @param listener
*/
public void attachTo(@Nullable Listener listener) {
OutputStream stdout = new ConsoleAwareOutputStream(this, NORMAL_OUTPUT, listener);
OutputStream stderr = new ConsoleAwareOutputStream(this, ERROR_OUTPUT, listener);
System.setOut(new PrintStream(stdout));
System.setErr(new PrintStream(stderr));
}
/**
* Close Stream
*/
void close() {
try {
Closeables.close(myOutput, true);
Closeables.close(myStdErr, true);
} catch (IOException e) {
}
}
/**
* Get the error ouput
* @return
*/
@NotNull
public String getStdErr() {
return myStdErr.toString();
}
/**
* Writer Parser
* @param contentType
* @param b
* @param off
* @param len
*/
public void write(@NotNull ConsoleViewContentType contentType, @NotNull byte[] b, int off, int len) {
boolean addNewLine = false;
if (contentType != myPreviousContentType) {
addNewLine = myPreviousContentType != null;
myPreviousContentType = contentType;
}
String lineSeparator = System.getProperty("line.separator");
boolean newLineAdded = false;
if (addNewLine) {
byte[] bytes = lineSeparator.getBytes();
myOutput.write(bytes, 0, bytes.length);
myConsoleView.print(lineSeparator, contentType);
newLineAdded = true;
}
String text = new String(b, off, len);
if (lineSeparator.equals(text) && newLineAdded) {
return;
}
myOutput.write(b, off, len);
if (contentType == ERROR_OUTPUT) {
myStdErr.write(b, off, len);
}
myConsoleView.print(text, contentType);
}
/**
* Standard output
* @return
*/
@Override
public String toString() {
return myOutput.toString();
}
/**
* Listener interface
*/
interface Listener {
void onOutput(@NotNull ConsoleViewContentType contentType, @NotNull byte[] data, int offset, int length);
}
/**
* Handles incoming text
*/
@AllArgsConstructor
public class ConsoleAwareOutputStream extends OutputStream {
@NotNull
private final EmbeddedLinuxJVMOutputForwarder myOutput;
@NotNull
private final ConsoleViewContentType myContentType;
@Nullable
private final Listener myListener;
/**
* Do Nothing
* @param b
*/
@Override
public void write(int b) {
}
@Override
public void write(@NotNull byte[] b, int off, int len) {
if (myListener != null) {
myListener.onOutput(myContentType, b, off, len);
}
myOutput.write(myContentType, b, off, len);
}
}
}