Skip to content

Commit

Permalink
Support for out or err stream for the terminal (fixes #787) (#788)
Browse files Browse the repository at this point in the history
* Fix formatting
* Move codepage support into the TerminalBuilder
* The PATH environment variable is iterated in reverse order
* Support out and err streams, introduce a TerminalProvider
  • Loading branch information
gnodet committed Jan 16, 2023
1 parent c2a0c9e commit d6e84da
Show file tree
Hide file tree
Showing 37 changed files with 1,058 additions and 552 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.10.1</version>
<configuration>
<showWarnings>true</showWarnings>
<compilerArgs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private String computeGroupPost(List<Candidate> c, boolean autoGroup, boolean gr
public void testConEmuLineReaderClearScreen() throws IOException {
System.setProperty("org.jline.terminal.conemu.disable-activate", "false");
StringWriter sw = new StringWriter();
AbstractWindowsTerminal terminal = new AbstractWindowsTerminal(new BufferedWriter(sw), "name", TYPE_WINDOWS_CONEMU, Charset.defaultCharset(), 0,
AbstractWindowsTerminal terminal = new AbstractWindowsTerminal(new BufferedWriter(sw), "name", TYPE_WINDOWS_CONEMU, Charset.defaultCharset(),
false, Terminal.SignalHandler.SIG_DFL) {
@Override
protected int getConsoleMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private static class TestTerminal extends AbstractWindowsTerminal {
public TestTerminal(StringWriter sw) throws IOException {
super(new AnsiWriter(new BufferedWriter(sw)), "name",
AbstractWindowsTerminal.TYPE_DUMB,
Charset.defaultCharset(), 0,
Charset.defaultCharset(),
false, SignalHandler.SIG_DFL);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.impl.AbstractPty;
import org.jline.terminal.spi.TerminalProvider;
import org.jline.terminal.spi.Pty;
import org.jline.utils.OSUtils;

Expand All @@ -24,8 +25,8 @@
import java.lang.reflect.Constructor;

import static org.fusesource.jansi.internal.CLibrary.TCSANOW;
import static org.jline.terminal.impl.jansi.JansiSupportImpl.JANSI_MAJOR_VERSION;
import static org.jline.terminal.impl.jansi.JansiSupportImpl.JANSI_MINOR_VERSION;
import static org.jline.terminal.impl.jansi.JansiTerminalProvider.JANSI_MAJOR_VERSION;
import static org.jline.terminal.impl.jansi.JansiTerminalProvider.JANSI_MINOR_VERSION;
import static org.jline.utils.ExecHelper.exec;

public abstract class JansiNativePty extends AbstractPty implements Pty {
Expand Down Expand Up @@ -172,11 +173,22 @@ protected static FileDescriptor newDescriptor(int fd) {
}
}

public static boolean isConsoleOutput() {
return CLibrary.isatty(1) == 1;
public static boolean isPosixSystemStream(TerminalProvider.Stream stream) {
switch (stream) {
case Input: return CLibrary.isatty(0) == 1;
case Output: return CLibrary.isatty(1) == 1;
case Error: return CLibrary.isatty(2) == 1;
default: return false;
}
}

public static boolean isConsoleInput() {
return CLibrary.isatty(0) == 1;
public static String posixSystemStreamName(TerminalProvider.Stream stream) {
switch (stream) {
case Input: return CLibrary.ttyname(0);
case Output: return CLibrary.ttyname(1);
case Error: return CLibrary.ttyname(2);
default: return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.impl.PosixPtyTerminal;
import org.jline.terminal.impl.PosixSysTerminal;
import org.jline.terminal.impl.jansi.freebsd.FreeBsdNativePty;
import org.jline.terminal.impl.jansi.linux.LinuxNativePty;
import org.jline.terminal.impl.jansi.osx.OsXNativePty;
import org.jline.terminal.impl.jansi.win.JansiWinSysTerminal;
import org.jline.terminal.spi.JansiSupport;
import org.jline.terminal.spi.Pty;
import org.jline.terminal.spi.TerminalProvider;
import org.jline.utils.OSUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JansiSupportImpl implements JansiSupport {
public class JansiTerminalProvider implements TerminalProvider {

static final int JANSI_MAJOR_VERSION;
static final int JANSI_MINOR_VERSION;
Expand Down Expand Up @@ -74,27 +77,30 @@ public static boolean isAtLeast(int major, int minor) {
}

@Override
public Pty current() throws IOException {
public String name() {
return "jansi";
}

public Pty current(Stream consoleStream) throws IOException {
String osName = System.getProperty("os.name");
if (osName.startsWith("Linux")) {
return LinuxNativePty.current();
return LinuxNativePty.current(consoleStream);
}
else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
return OsXNativePty.current();
return OsXNativePty.current(consoleStream);
}
else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
// Solaris is not supported by jansi
// return SolarisNativePty.current();
}
else if (osName.startsWith("FreeBSD")) {
if (isAtLeast(1, 16)) {
return FreeBsdNativePty.current();
return FreeBsdNativePty.current(consoleStream);
}
}
throw new UnsupportedOperationException();
}

@Override
public Pty open(Attributes attributes, Size size) throws IOException {
if (isAtLeast(1, 16)) {
String osName = System.getProperty("os.name");
Expand All @@ -116,14 +122,23 @@ else if (osName.startsWith("FreeBSD")) {
}

@Override
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException {
return winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, false);
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream) throws IOException {
if (OSUtils.IS_WINDOWS) {
return winSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream );
} else {
return posixSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream );
}
}

@Override
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException {
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough,
Charset encoding, boolean nativeSignals,
Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream) throws IOException {
if (isAtLeast(1, 12)) {
JansiWinSysTerminal terminal = JansiWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused);
JansiWinSysTerminal terminal = JansiWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding,
nativeSignals, signalHandler, paused, consoleStream);
if (!isAtLeast(1, 16)) {
terminal.disableScrolling();
}
Expand All @@ -132,37 +147,46 @@ public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough
throw new UnsupportedOperationException();
}

public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
Stream consoleStream) throws IOException {
Pty pty = current(consoleStream);
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler);
}

@Override
public boolean isWindowsConsole() {
return JansiWinSysTerminal.isWindowsConsole();
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out,
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused,
Attributes attributes, Size size) throws IOException
{
Pty pty = open(attributes, size);
return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
}

@Override
public boolean isConsoleOutput() {
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
if (isAtLeast(2,1)) {
return JansiNativePty.isConsoleOutput();
public boolean isSystemStream(Stream stream) {
try {
if (OSUtils.IS_WINDOWS) {
return isWindowsSystemStream(stream);
} else {
throw new UnsupportedOperationException();
return isPosixSystemStream(stream);
}
} else if (OSUtils.IS_WINDOWS) {
return JansiWinSysTerminal.isConsoleOutput();
} catch (Throwable t) {
return false;
}
return JansiNativePty.isConsoleOutput();
}

public boolean isWindowsSystemStream(Stream stream) {
return JansiWinSysTerminal.isWindowsSystemStream(stream);
}

public boolean isPosixSystemStream(Stream stream) {
return JansiNativePty.isPosixSystemStream(stream);
}

@Override
public boolean isConsoleInput() {
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
if (isAtLeast(2,1)) {
return JansiNativePty.isConsoleInput();
} else {
throw new UnsupportedOperationException();
}
} else if (OSUtils.IS_WINDOWS) {
return JansiWinSysTerminal.isConsoleInput();
}
return JansiNativePty.isConsoleInput();
public String systemStreamName(Stream stream) {
return JansiNativePty.posixSystemStreamName(stream);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.impl.jansi.JansiNativePty;
import org.jline.terminal.spi.TerminalProvider;

import java.io.FileDescriptor;
import java.io.IOException;
Expand All @@ -20,10 +21,16 @@

public class FreeBsdNativePty extends JansiNativePty {

public static FreeBsdNativePty current() throws IOException {
public static FreeBsdNativePty current(TerminalProvider.Stream consoleStream) throws IOException {
try {
String name = ttyname();
return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, name);
switch (consoleStream) {
case Output:
return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname());
case Error:
return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname());
default:
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
}
} catch (IOException e) {
throw new IOException("Not a tty", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.impl.jansi.JansiNativePty;
import org.jline.terminal.impl.jansi.osx.OsXNativePty;
import org.jline.terminal.spi.TerminalProvider;

import java.io.FileDescriptor;
import java.io.IOException;
Expand All @@ -21,10 +21,16 @@

public class LinuxNativePty extends JansiNativePty {

public static LinuxNativePty current() throws IOException {
public static LinuxNativePty current(TerminalProvider.Stream consoleStream) throws IOException {
try {
String name = ttyname();
return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, name);
switch (consoleStream) {
case Output:
return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname());
case Error:
return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname());
default:
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
}
} catch (IOException e) {
throw new IOException("Not a tty", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.impl.jansi.JansiNativePty;
import org.jline.terminal.spi.TerminalProvider;

import java.io.FileDescriptor;
import java.io.IOException;
Expand All @@ -20,10 +21,16 @@

public class OsXNativePty extends JansiNativePty {

public static OsXNativePty current() throws IOException {
public static OsXNativePty current(TerminalProvider.Stream consoleStream) throws IOException {
try {
String name = ttyname();
return new OsXNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, name);
switch (consoleStream) {
case Output:
return new OsXNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname());
case Error:
return new OsXNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname());
default:
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
}
} catch (IOException e) {
throw new IOException("Not a tty", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@

class JansiWinConsoleWriter extends AbstractWindowsConsoleWriter {

private static final long console = GetStdHandle(STD_OUTPUT_HANDLE);
private final long console;
private final int[] writtenChars = new int[1];

public JansiWinConsoleWriter(long console) {
this.console = console;
}

@Override
protected void writeConsole(char[] text, int len) throws IOException {
if (WriteConsoleW(console, text, len, writtenChars, 0) == 0) {
Expand Down
Loading

0 comments on commit d6e84da

Please sign in to comment.