diff --git a/jansi/src/main/java/org/fusesource/jansi/AnsiConsole.java b/jansi/src/main/java/org/fusesource/jansi/AnsiConsole.java
index 0721ddff..9a8978f5 100644
--- a/jansi/src/main/java/org/fusesource/jansi/AnsiConsole.java
+++ b/jansi/src/main/java/org/fusesource/jansi/AnsiConsole.java
@@ -16,11 +16,14 @@
package org.fusesource.jansi;
import java.io.BufferedOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.Locale;
@@ -28,6 +31,11 @@
import static org.fusesource.jansi.internal.CLibrary.STDERR_FILENO;
import static org.fusesource.jansi.internal.CLibrary.STDOUT_FILENO;
import static org.fusesource.jansi.internal.CLibrary.isatty;
+import static org.fusesource.jansi.internal.Kernel32.GetConsoleMode;
+import static org.fusesource.jansi.internal.Kernel32.GetStdHandle;
+import static org.fusesource.jansi.internal.Kernel32.STD_ERROR_HANDLE;
+import static org.fusesource.jansi.internal.Kernel32.STD_OUTPUT_HANDLE;
+import static org.fusesource.jansi.internal.Kernel32.SetConsoleMode;
/**
* Provides consistent access to an ANSI aware console PrintStream or an ANSI codes stripping PrintStream
@@ -56,25 +64,36 @@ public class AnsiConsole {
* ConEmu ANSI X3.64 support enabled,
* used by cmder
*/
+ @Deprecated
static final boolean IS_CON_EMU_ANSI = "ON".equals(System.getenv("ConEmuANSI"));
static final boolean IS_CYGWIN = IS_WINDOWS
&& System.getenv("PWD") != null
- && System.getenv("PWD").startsWith("/")
- && !"cygwin".equals(System.getenv("TERM"));
+ && System.getenv("PWD").startsWith("/");
+ @Deprecated
static final boolean IS_MINGW_XTERM = IS_WINDOWS
&& System.getenv("MSYSTEM") != null
&& System.getenv("MSYSTEM").startsWith("MINGW")
&& "xterm".equals(System.getenv("TERM"));
+ static final boolean IS_MSYSTEM = IS_WINDOWS
+ && System.getenv("MSYSTEM") != null
+ && (System.getenv("MSYSTEM").startsWith("MINGW")
+ || System.getenv("MSYSTEM").equals("MSYS"));
+
+ static final boolean IS_CONEMU = IS_WINDOWS
+ && System.getenv("ConEmuPID") != null;
+
+ static final int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
+
private static JansiOutputType jansiOutputType;
static final JansiOutputType JANSI_STDOUT_TYPE;
static final JansiOutputType JANSI_STDERR_TYPE;
static {
- out = wrapSystemOut(system_out);
+ out = ansiSystem(true);
JANSI_STDOUT_TYPE = jansiOutputType;
- err = wrapSystemErr(system_err);
+ err = ansiSystem(false);
JANSI_STDERR_TYPE = jansiOutputType;
}
@@ -83,6 +102,112 @@ public class AnsiConsole {
private AnsiConsole() {
}
+ private static PrintStream ansiSystem(boolean stdout) {
+ OutputStream out = new BufferedNoSyncOutputStream(new FileOutputStream(stdout ? FileDescriptor.out : FileDescriptor.err));
+
+ String enc = System.getProperty(stdout ? "sun.stdout.encoding" : "sun.stderr.encoding");
+
+ // If the jansi.passthrough property is set, then don't interpret
+ // any of the ansi sequences.
+ if (Boolean.getBoolean("jansi.passthrough")) {
+ jansiOutputType = JansiOutputType.PASSTHROUGH;
+ return newPrintStream(out, enc);
+ }
+
+ // If the jansi.strip property is set, then we just strip the
+ // the ansi escapes.
+ if (Boolean.getBoolean("jansi.strip")) {
+ jansiOutputType = JansiOutputType.STRIP_ANSI;
+ return new PrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), true);
+ }
+
+ if (IS_WINDOWS) {
+ long console = GetStdHandle(stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+ int[] mode = new int[1];
+ if (GetConsoleMode(console, mode) != 0
+ && SetConsoleMode(console, mode[0] | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) {
+ jansiOutputType = JansiOutputType.PASSTHROUGH;
+ return newPrintStream(out, enc);
+ }
+ }
+
+ if (IS_WINDOWS && !(IS_CON_EMU_ANSI || IS_CYGWIN || IS_MINGW_XTERM)) {
+
+ // On Windows, when no ANSI-capable terminal is used, we know the console does not natively interpret ANSI
+ // codes but we can use jansi-native Kernel32 API for console
+ try {
+ jansiOutputType = JansiOutputType.WINDOWS;
+ return newPrintStream(new AnsiNoSyncOutputStream(out, new WindowsAnsiProcessor(out, stdout)), enc);
+ } catch (Throwable ignore) {
+ // this happens when JNA is not in the path.. or
+ // this happens when the stdout is being redirected to a file.
+ }
+
+ // Use the ANSIOutputStream to strip out the ANSI escape sequences.
+ jansiOutputType = JansiOutputType.STRIP_ANSI;
+ return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), enc);
+ }
+
+ // We must be on some Unix variant or ANSI-enabled ConEmu, Cygwin or MSYS(2) on Windows...
+ try {
+ // If the jansi.force property is set, then we force to output
+ // the ansi escapes for piping it into ansi color aware commands (e.g. less -r)
+ boolean forceColored = Boolean.getBoolean("jansi.force");
+ // If we can detect that stdout is not a tty.. then setup
+ // to strip the ANSI sequences..
+ if (!forceColored && isatty(stdout ? 1 : 2) == 0) {
+ jansiOutputType = JansiOutputType.STRIP_ANSI;
+ return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), enc);
+ }
+ } catch (Throwable ignore) {
+ // These errors happen if the JNI lib is not available for your platform.
+ // But since we are on ANSI friendly platform, assume the user is on the console.
+ }
+
+ // By default we assume your Unix tty can handle ANSI codes.
+ // Just wrap it up so that when we get closed, we reset the
+ // attributes.
+ jansiOutputType = JansiOutputType.RESET_ANSI_AT_CLOSE;
+ return newPrintStream(out, enc, AnsiNoSyncOutputStream.RESET_CODE);
+ }
+
+ private static PrintStream newPrintStream(OutputStream out, String enc) {
+ return newPrintStream(out, enc, null);
+ }
+
+ private static PrintStream newPrintStream(OutputStream out, String enc, byte[] reset) {
+ if (enc != null) {
+ try {
+ return new ResetAtClosePrintStream(out, enc, reset);
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+ return new ResetAtClosePrintStream(out, reset);
+ }
+
+ static class ResetAtClosePrintStream extends PrintStream {
+
+ private final byte[] reset;
+
+ public ResetAtClosePrintStream(OutputStream out, byte[] reset) {
+ super(out, true);
+ this.reset = reset;
+ }
+
+ public ResetAtClosePrintStream(OutputStream out, String encoding, byte[] reset) throws UnsupportedEncodingException {
+ super(out, true, encoding);
+ this.reset = reset;
+ }
+
+ @Override
+ public void close() {
+ if (reset != null) {
+ write(reset, 0, reset.length);
+ }
+ super.close();
+ }
+ }
+
@Deprecated
public static OutputStream wrapOutputStream(final OutputStream stream) {
try {