diff --git a/reader/src/test/java/org/jline/reader/impl/LineReaderTest.java b/reader/src/test/java/org/jline/reader/impl/LineReaderTest.java index 584f433bb..e085b3c03 100644 --- a/reader/src/test/java/org/jline/reader/impl/LineReaderTest.java +++ b/reader/src/test/java/org/jline/reader/impl/LineReaderTest.java @@ -114,6 +114,8 @@ public void testConEmuLineReaderClearScreen() throws IOException { StringWriter sw = new StringWriter(); AbstractWindowsTerminal terminal = new AbstractWindowsTerminal( + null, + null, new BufferedWriter(sw), "name", TYPE_WINDOWS_CONEMU, diff --git a/reader/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java b/reader/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java index db6b0b871..f3dee5e62 100644 --- a/reader/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java +++ b/reader/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java @@ -83,6 +83,8 @@ private void process(TestTerminal terminal, int c) { private static class TestTerminal extends AbstractWindowsTerminal { public TestTerminal(StringWriter sw) throws IOException { super( + null, + null, new AnsiWriter(new BufferedWriter(sw)), "name", AbstractWindowsTerminal.TYPE_DUMB, diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/CLibrary.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/CLibrary.java index c694b6839..d042fc01d 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/CLibrary.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/CLibrary.java @@ -17,6 +17,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.TerminalProvider; @SuppressWarnings("preview") class CLibrary { @@ -482,7 +483,7 @@ static String ttyName(int fd) { } } - static Pty openpty(Attributes attr, Size size) { + static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { try { java.lang.foreign.MemorySegment buf = java.lang.foreign.Arena.ofAuto().allocate(64); @@ -504,7 +505,8 @@ static Pty openpty(Attributes attr, Size size) { len++; } String device = new String(str, 0, len); - return new FfmNativePty(master.get(ValueLayout.JAVA_INT, 0), slave.get(ValueLayout.JAVA_INT, 0), device); + return new FfmNativePty( + provider, null, master.get(ValueLayout.JAVA_INT, 0), slave.get(ValueLayout.JAVA_INT, 0), device); } catch (Throwable e) { throw new RuntimeException("Unable to call openpty()", e); } diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmNativePty.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmNativePty.java index 5ede7ed1b..f95e2acef 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmNativePty.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmNativePty.java @@ -18,6 +18,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractPty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; class FfmNativePty extends AbstractPty { @@ -29,11 +30,22 @@ class FfmNativePty extends AbstractPty { private final FileDescriptor slaveFD; private final FileDescriptor slaveOutFD; - public FfmNativePty(int master, int slave, String name) { - this(master, newDescriptor(master), slave, newDescriptor(slave), slave, newDescriptor(slave), name); + public FfmNativePty(TerminalProvider provider, SystemStream systemStream, int master, int slave, String name) { + this( + provider, + systemStream, + master, + newDescriptor(master), + slave, + newDescriptor(slave), + slave, + newDescriptor(slave), + name); } public FfmNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -41,6 +53,7 @@ public FfmNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { + super(provider, systemStream); this.master = master; this.slave = slave; this.slaveOut = slaveOut; @@ -129,7 +142,7 @@ public String toString() { return "FfmNativePty[" + getName() + "]"; } - public static boolean isPosixSystemStream(TerminalProvider.Stream stream) { + public static boolean isPosixSystemStream(SystemStream stream) { switch (stream) { case Input: return CLibrary.isTty(0); @@ -142,7 +155,7 @@ public static boolean isPosixSystemStream(TerminalProvider.Stream stream) { } } - public static String posixSystemStreamName(TerminalProvider.Stream stream) { + public static String posixSystemStreamName(SystemStream stream) { switch (stream) { case Input: return CLibrary.ttyName(0); @@ -154,4 +167,9 @@ public static String posixSystemStreamName(TerminalProvider.Stream stream) { throw new IllegalArgumentException(); } } + + public static int systemStreamWidth(SystemStream systemStream) { + int fd = systemStream == SystemStream.Output ? 1 : 2; + return CLibrary.getTerminalSize(fd).getColumns(); + } } diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java index a0e94a9d3..ac13d1e1a 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java @@ -20,6 +20,7 @@ import org.jline.terminal.impl.PosixPtyTerminal; import org.jline.terminal.impl.PosixSysTerminal; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -46,19 +47,21 @@ public Terminal sysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (OSUtils.IS_WINDOWS) { return NativeWinSysTerminal.createTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused); } else { Pty pty = new FfmNativePty( + this, + systemStream, -1, null, 0, FileDescriptor.in, - consoleStream == Stream.Output ? 1 : 2, - consoleStream == Stream.Output ? FileDescriptor.out : FileDescriptor.err, + systemStream == SystemStream.Output ? 1 : 2, + systemStream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err, CLibrary.ttyName(0)); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler); } @@ -76,12 +79,12 @@ public Terminal newTerminal( Attributes attributes, Size size) throws IOException { - Pty pty = CLibrary.openpty(attributes, size); + Pty pty = CLibrary.openpty(this, attributes, size); return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused); } @Override - public boolean isSystemStream(Stream stream) { + public boolean isSystemStream(SystemStream stream) { if (OSUtils.IS_WINDOWS) { return isWindowsSystemStream(stream); } else { @@ -89,16 +92,21 @@ public boolean isSystemStream(Stream stream) { } } - public boolean isWindowsSystemStream(Stream stream) { + public boolean isWindowsSystemStream(SystemStream stream) { return NativeWinSysTerminal.isWindowsSystemStream(stream); } - public boolean isPosixSystemStream(Stream stream) { + public boolean isPosixSystemStream(SystemStream stream) { return FfmNativePty.isPosixSystemStream(stream); } @Override - public String systemStreamName(Stream stream) { + public String systemStreamName(SystemStream stream) { return FfmNativePty.posixSystemStreamName(stream); } + + @Override + public int systemStreamWidth(SystemStream stream) { + return FfmNativePty.systemStreamWidth(stream); + } } diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinSysTerminal.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinSysTerminal.java index 411f0768f..2a2548f72 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinSysTerminal.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinSysTerminal.java @@ -18,6 +18,7 @@ import org.jline.terminal.Cursor; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractWindowsTerminal; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -41,14 +42,15 @@ public class NativeWinSysTerminal extends AbstractWindowsTerminal { public static NativeWinSysTerminal createTerminal( + TerminalProvider provider, + SystemStream systemStream, String name, String type, boolean ansiPassThrough, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, - boolean paused, - TerminalProvider.Stream consoleStream) + boolean paused) throws IOException { try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) { // Get input console mode @@ -59,7 +61,7 @@ public static NativeWinSysTerminal createTerminal( } // Get output console and mode java.lang.foreign.MemorySegment console; - switch (consoleStream) { + switch (systemStream) { case Output: console = GetStdHandle(STD_OUTPUT_HANDLE); break; @@ -67,7 +69,7 @@ public static NativeWinSysTerminal createTerminal( console = GetStdHandle(STD_ERROR_HANDLE); break; default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } java.lang.foreign.MemorySegment outMode = allocateInt(arena); if (GetConsoleMode(console, outMode) == 0) { @@ -93,6 +95,8 @@ public static NativeWinSysTerminal createTerminal( } // Create terminal NativeWinSysTerminal terminal = new NativeWinSysTerminal( + provider, + systemStream, writer, name, type, @@ -115,7 +119,7 @@ private static boolean enableVtp(java.lang.foreign.MemorySegment console, int m) return SetConsoleMode(console, m | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0; } - public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { + public static boolean isWindowsSystemStream(SystemStream stream) { try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) { java.lang.foreign.MemorySegment console; java.lang.foreign.MemorySegment mode = allocateInt(arena); @@ -141,6 +145,8 @@ private static java.lang.foreign.MemorySegment allocateInt(java.lang.foreign.Are } NativeWinSysTerminal( + TerminalProvider provider, + SystemStream systemStream, Writer writer, String name, String type, @@ -153,6 +159,8 @@ private static java.lang.foreign.MemorySegment allocateInt(java.lang.foreign.Are int outConsoleMode) throws IOException { super( + provider, + systemStream, writer, name, type, diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiNativePty.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiNativePty.java index ae9b36dd9..f17e7061e 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiNativePty.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiNativePty.java @@ -16,10 +16,13 @@ import java.io.OutputStream; import org.fusesource.jansi.internal.CLibrary; +import org.fusesource.jansi.internal.Kernel32; import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractPty; +import org.jline.terminal.impl.jansi.win.JansiWinSysTerminal; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -38,11 +41,20 @@ public abstract class JansiNativePty extends AbstractPty implements Pty { private final FileDescriptor slaveFD; private final FileDescriptor slaveOutFD; - public JansiNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - this(master, masterFD, slave, slaveFD, slave, slaveFD, name); + public JansiNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + this(provider, systemStream, master, masterFD, slave, slaveFD, slave, slaveFD, name); } public JansiNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -50,6 +62,7 @@ public JansiNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { + super(provider, systemStream); this.master = master; this.slave = slave; this.slaveOut = slaveOut; @@ -174,29 +187,44 @@ public String toString() { return "JansiNativePty[" + getName() + "]"; } - 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 isPosixSystemStream(SystemStream stream) { + return CLibrary.isatty(fd(stream)) == 1; + } + + public static String posixSystemStreamName(SystemStream systemStream) { + return CLibrary.ttyname(fd(systemStream)); + } + + public static int systemStreamWidth(SystemStream systemStream) { + try { + if (OSUtils.IS_WINDOWS) { + Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO(); + long outConsole = JansiWinSysTerminal.getConsole(systemStream); + Kernel32.GetConsoleScreenBufferInfo(outConsole, info); + return info.windowWidth(); + } else { + CLibrary.WinSize sz = new CLibrary.WinSize(); + int res = CLibrary.ioctl(fd(systemStream), CLibrary.TIOCGWINSZ, sz); + if (res != 0) { + throw new IOException("Error calling ioctl(TIOCGWINSZ): return code is " + res); + } + return sz.ws_col; + } + } catch (Throwable t) { + return -1; } } - public static String posixSystemStreamName(TerminalProvider.Stream stream) { - switch (stream) { + private static int fd(SystemStream systemStream) { + switch (systemStream) { case Input: - return CLibrary.ttyname(0); + return 0; case Output: - return CLibrary.ttyname(1); + return 1; case Error: - return CLibrary.ttyname(2); + return 2; default: - return null; + return -1; } } } diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiTerminalProvider.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiTerminalProvider.java index 7277661d7..4d01ba644 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiTerminalProvider.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/JansiTerminalProvider.java @@ -27,6 +27,7 @@ import org.jline.terminal.impl.jansi.osx.OsXNativePty; import org.jline.terminal.impl.jansi.win.JansiWinSysTerminal; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -82,18 +83,18 @@ public String name() { return "jansi"; } - public Pty current(Stream consoleStream) throws IOException { + public Pty current(SystemStream systemStream) throws IOException { String osName = System.getProperty("os.name"); if (osName.startsWith("Linux")) { - return LinuxNativePty.current(consoleStream); + return LinuxNativePty.current(this, systemStream); } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) { - return OsXNativePty.current(consoleStream); + return OsXNativePty.current(this, systemStream); } 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(consoleStream); + return FreeBsdNativePty.current(this, systemStream); } } throw new UnsupportedOperationException(); @@ -103,14 +104,14 @@ public Pty open(Attributes attributes, Size size) throws IOException { if (isAtLeast(1, 16)) { String osName = System.getProperty("os.name"); if (osName.startsWith("Linux")) { - return LinuxNativePty.open(attributes, size); + return LinuxNativePty.open(this, attributes, size); } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) { - return OsXNativePty.open(attributes, size); + return OsXNativePty.open(this, attributes, size); } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) { // Solaris is not supported by jansi // return SolarisNativePty.current(); } else if (osName.startsWith("FreeBSD")) { - return FreeBsdNativePty.open(attributes, size); + return FreeBsdNativePty.open(this, attributes, size); } } throw new UnsupportedOperationException(); @@ -125,14 +126,14 @@ public Terminal sysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (OSUtils.IS_WINDOWS) { return winSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } else { return posixSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } } @@ -144,11 +145,11 @@ public Terminal winSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (isAtLeast(1, 12)) { JansiWinSysTerminal terminal = JansiWinSysTerminal.createTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused); if (!isAtLeast(1, 16)) { terminal.disableScrolling(); } @@ -165,9 +166,9 @@ public Terminal posixSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { - Pty pty = current(consoleStream); + Pty pty = current(systemStream); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler); } @@ -188,7 +189,7 @@ public Terminal newTerminal( } @Override - public boolean isSystemStream(Stream stream) { + public boolean isSystemStream(SystemStream stream) { try { if (OSUtils.IS_WINDOWS) { return isWindowsSystemStream(stream); @@ -200,16 +201,21 @@ public boolean isSystemStream(Stream stream) { } } - public boolean isWindowsSystemStream(Stream stream) { + public boolean isWindowsSystemStream(SystemStream stream) { return JansiWinSysTerminal.isWindowsSystemStream(stream); } - public boolean isPosixSystemStream(Stream stream) { + public boolean isPosixSystemStream(SystemStream stream) { return JansiNativePty.isPosixSystemStream(stream); } @Override - public String systemStreamName(Stream stream) { + public String systemStreamName(SystemStream stream) { return JansiNativePty.posixSystemStreamName(stream); } + + @Override + public int systemStreamWidth(SystemStream stream) { + return JansiNativePty.systemStreamWidth(stream); + } } diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/freebsd/FreeBsdNativePty.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/freebsd/FreeBsdNativePty.java index 758b821f3..21e8c8518 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/freebsd/FreeBsdNativePty.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/freebsd/FreeBsdNativePty.java @@ -17,26 +17,29 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jansi.JansiNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; public class FreeBsdNativePty extends JansiNativePty { - public static FreeBsdNativePty current(TerminalProvider.Stream consoleStream) throws IOException { + public static FreeBsdNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { try { - switch (consoleStream) { + switch (systemStream) { case Output: - return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname()); + return new FreeBsdNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname()); case Error: - return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname()); + return new FreeBsdNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname()); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } catch (IOException e) { throw new IOException("Not a tty", e); } } - public static FreeBsdNativePty open(Attributes attr, Size size) throws IOException { + public static FreeBsdNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -51,14 +54,24 @@ public static FreeBsdNativePty open(Attributes attr, Size size) throws IOExcepti len++; } String name = new String(buf, 0, len); - return new FreeBsdNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new FreeBsdNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public FreeBsdNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public FreeBsdNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public FreeBsdNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -66,7 +79,7 @@ public FreeBsdNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } // CONSTANTS diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/linux/LinuxNativePty.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/linux/LinuxNativePty.java index 3ee690feb..0cdc47922 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/linux/LinuxNativePty.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/linux/LinuxNativePty.java @@ -17,26 +17,29 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jansi.JansiNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; public class LinuxNativePty extends JansiNativePty { - public static LinuxNativePty current(TerminalProvider.Stream consoleStream) throws IOException { + public static LinuxNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { try { - switch (consoleStream) { + switch (systemStream) { case Output: - return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname()); + return new LinuxNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname()); case Error: - return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname()); + return new LinuxNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname()); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } catch (IOException e) { throw new IOException("Not a tty", e); } } - public static LinuxNativePty open(Attributes attr, Size size) throws IOException { + public static LinuxNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -51,14 +54,21 @@ public static LinuxNativePty open(Attributes attr, Size size) throws IOException len++; } String name = new String(buf, 0, len); - return new LinuxNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); - } - - public LinuxNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + return new LinuxNativePty( + provider, + null, + master[0], + newDescriptor(master[0]), + slave[0], + newDescriptor(slave[0]), + 2, + FileDescriptor.err, + name); } public LinuxNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -66,7 +76,7 @@ public LinuxNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } // CONSTANTS diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/osx/OsXNativePty.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/osx/OsXNativePty.java index 99940619d..734327cf0 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/osx/OsXNativePty.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/osx/OsXNativePty.java @@ -17,26 +17,45 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jansi.JansiNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; public class OsXNativePty extends JansiNativePty { - public static OsXNativePty current(TerminalProvider.Stream consoleStream) throws IOException { + public static OsXNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { try { - switch (consoleStream) { + switch (systemStream) { case Output: - return new OsXNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname()); + return new OsXNativePty( + provider, + SystemStream.Output, + -1, + null, + 0, + FileDescriptor.in, + 1, + FileDescriptor.out, + ttyname()); case Error: - return new OsXNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname()); + return new OsXNativePty( + provider, + SystemStream.Error, + -1, + null, + 0, + FileDescriptor.in, + 2, + FileDescriptor.err, + ttyname()); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } catch (IOException e) { throw new IOException("Not a tty", e); } } - public static OsXNativePty open(Attributes attr, Size size) throws IOException { + public static OsXNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -51,14 +70,24 @@ public static OsXNativePty open(Attributes attr, Size size) throws IOException { len++; } String name = new String(buf, 0, len); - return new OsXNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new OsXNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public OsXNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public OsXNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public OsXNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -66,8 +95,9 @@ public OsXNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } + // CONSTANTS private static final int VEOF = 0; diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/solaris/SolarisNativePty.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/solaris/SolarisNativePty.java index e0b3d57b2..fda654258 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/solaris/SolarisNativePty.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/solaris/SolarisNativePty.java @@ -16,23 +16,35 @@ import org.fusesource.jansi.internal.CLibrary; import org.jline.terminal.Attributes; import org.jline.terminal.impl.jansi.JansiNativePty; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; public class SolarisNativePty extends JansiNativePty { - public static SolarisNativePty current() throws IOException { + public static SolarisNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { try { String name = ttyname(); - return new SolarisNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, name); + return new SolarisNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, name); } catch (IOException e) { throw new IOException("Not a tty", e); } } - public SolarisNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public SolarisNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public SolarisNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -40,7 +52,7 @@ public SolarisNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } // CONSTANTS diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java index 483405954..42b666eeb 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java @@ -23,6 +23,7 @@ import org.jline.terminal.Cursor; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractWindowsTerminal; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.InfoCmp; import org.jline.utils.OSUtils; @@ -46,14 +47,15 @@ public class JansiWinSysTerminal extends AbstractWindowsTerminal { private static final long consoleErr = GetStdHandle(STD_ERROR_HANDLE); public static JansiWinSysTerminal createTerminal( + TerminalProvider provider, + SystemStream systemStream, String name, String type, boolean ansiPassThrough, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, - boolean paused, - TerminalProvider.Stream consoleStream) + boolean paused) throws IOException { // Get input console mode int[] inMode = new int[1]; @@ -61,17 +63,7 @@ public static JansiWinSysTerminal createTerminal( throw new IOException("Failed to get console mode: " + getLastErrorMessage()); } // Get output console and mode - long console; - switch (consoleStream) { - case Output: - console = consoleOut; - break; - case Error: - console = consoleErr; - break; - default: - throw new IllegalArgumentException("Unsupported stream for console: " + consoleStream); - } + long console = getConsole(systemStream); int[] outMode = new int[1]; if (Kernel32.GetConsoleMode(console, outMode) == 0) { throw new IOException("Failed to get console mode: " + getLastErrorMessage()); @@ -95,7 +87,18 @@ public static JansiWinSysTerminal createTerminal( } // Create terminal JansiWinSysTerminal terminal = new JansiWinSysTerminal( - writer, name, type, encoding, nativeSignals, signalHandler, consoleIn, inMode[0], console, outMode[0]); + provider, + systemStream, + writer, + name, + type, + encoding, + nativeSignals, + signalHandler, + consoleIn, + inMode[0], + console, + outMode[0]); // Start input pump thread if (!paused) { terminal.resume(); @@ -103,6 +106,21 @@ public static JansiWinSysTerminal createTerminal( return terminal; } + public static long getConsole(SystemStream systemStream) { + long console; + switch (systemStream) { + case Output: + console = consoleOut; + break; + case Error: + console = consoleErr; + break; + default: + throw new IllegalArgumentException("Unsupported stream for console: " + systemStream); + } + return console; + } + private static boolean enableVtp(long console, int outMode) { return Kernel32.SetConsoleMode(console, outMode | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0; @@ -112,7 +130,7 @@ private static Writer newConsoleWriter(long console) { return new JansiWinConsoleWriter(console); } - public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { + public static boolean isWindowsSystemStream(SystemStream stream) { int[] mode = new int[1]; long console; switch (stream) { @@ -132,6 +150,8 @@ public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { } JansiWinSysTerminal( + TerminalProvider provider, + SystemStream systemStream, Writer writer, String name, String type, @@ -143,7 +163,19 @@ public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { long outConsole, int outMode) throws IOException { - super(writer, name, type, encoding, nativeSignals, signalHandler, inConsole, inMode, outConsole, outMode); + super( + provider, + systemStream, + writer, + name, + type, + encoding, + nativeSignals, + signalHandler, + inConsole, + inMode, + outConsole, + outMode); } @Override diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaNativePty.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaNativePty.java index 0227dac0a..c39feb4f9 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaNativePty.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaNativePty.java @@ -23,6 +23,7 @@ import org.jline.terminal.impl.jna.osx.OsXNativePty; import org.jline.terminal.impl.jna.solaris.SolarisNativePty; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import com.sun.jna.Platform; @@ -37,45 +38,54 @@ public abstract class JnaNativePty extends AbstractPty implements Pty { private final FileDescriptor slaveFD; private final FileDescriptor slaveOutFD; - public static JnaNativePty current(TerminalProvider.Stream console) throws IOException { + public static JnaNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { if (Platform.isMac()) { if (Platform.is64Bit() && Platform.isARM()) { throw new UnsupportedOperationException(); } - return OsXNativePty.current(console); + return OsXNativePty.current(provider, systemStream); } else if (Platform.isLinux()) { - return LinuxNativePty.current(console); + return LinuxNativePty.current(provider, systemStream); } else if (Platform.isSolaris()) { - return SolarisNativePty.current(console); + return SolarisNativePty.current(provider, systemStream); } else if (Platform.isFreeBSD()) { - return FreeBsdNativePty.current(console); + return FreeBsdNativePty.current(provider, systemStream); } else { throw new UnsupportedOperationException(); } } - public static JnaNativePty open(Attributes attr, Size size) throws IOException { + public static JnaNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { if (Platform.isMac()) { if (Platform.is64Bit() && Platform.isARM()) { throw new UnsupportedOperationException(); } - return OsXNativePty.open(attr, size); + return OsXNativePty.open(provider, attr, size); } else if (Platform.isLinux()) { - return LinuxNativePty.open(attr, size); + return LinuxNativePty.open(provider, attr, size); } else if (Platform.isSolaris()) { - return SolarisNativePty.open(attr, size); + return SolarisNativePty.open(provider, attr, size); } else if (Platform.isFreeBSD()) { - return FreeBsdNativePty.open(attr, size); + return FreeBsdNativePty.open(provider, attr, size); } else { throw new UnsupportedOperationException(); } } - protected JnaNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - this(master, masterFD, slave, slaveFD, slave, slaveFD, name); + protected JnaNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + this(provider, systemStream, master, masterFD, slave, slaveFD, slave, slaveFD, name); } protected JnaNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -83,6 +93,7 @@ protected JnaNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { + super(provider, systemStream); this.master = master; this.slave = slave; this.slaveOut = slaveOut; @@ -151,7 +162,7 @@ public String toString() { return "JnaNativePty[" + getName() + "]"; } - public static boolean isPosixSystemStream(TerminalProvider.Stream stream) { + public static boolean isPosixSystemStream(SystemStream stream) { switch (stream) { case Input: return isatty(0); @@ -164,7 +175,7 @@ public static boolean isPosixSystemStream(TerminalProvider.Stream stream) { } } - public static String posixSystemStreamName(TerminalProvider.Stream stream) { + public static String posixSystemStreamName(SystemStream stream) { switch (stream) { case Input: return ttyname(0); diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaTerminalProvider.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaTerminalProvider.java index 09e3fbaca..7dc64e4dd 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaTerminalProvider.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/JnaTerminalProvider.java @@ -20,6 +20,7 @@ import org.jline.terminal.impl.PosixSysTerminal; import org.jline.terminal.impl.jna.win.JnaWinSysTerminal; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -29,12 +30,12 @@ public String name() { return "jna"; } - public Pty current(TerminalProvider.Stream console) throws IOException { - return JnaNativePty.current(console); + public Pty current(SystemStream systemStream) throws IOException { + return JnaNativePty.current(this, systemStream); } public Pty open(Attributes attributes, Size size) throws IOException { - return JnaNativePty.open(attributes, size); + return JnaNativePty.open(this, attributes, size); } @Override @@ -46,14 +47,14 @@ public Terminal sysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (OSUtils.IS_WINDOWS) { return winSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } else { return posixSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } } @@ -65,10 +66,10 @@ public Terminal winSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream console) + SystemStream systemStream) throws IOException { return JnaWinSysTerminal.createTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, console); + this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused); } public Terminal posixSysTerminal( @@ -79,9 +80,9 @@ public Terminal posixSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { - Pty pty = current(consoleStream); + Pty pty = current(systemStream); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler); } @@ -102,7 +103,7 @@ public Terminal newTerminal( } @Override - public boolean isSystemStream(Stream stream) { + public boolean isSystemStream(SystemStream stream) { try { if (OSUtils.IS_WINDOWS) { return isWindowsSystemStream(stream); @@ -114,20 +115,29 @@ public boolean isSystemStream(Stream stream) { } } - public boolean isWindowsSystemStream(Stream stream) { + public boolean isWindowsSystemStream(SystemStream stream) { return JnaWinSysTerminal.isWindowsSystemStream(stream); } - public boolean isPosixSystemStream(Stream stream) { + public boolean isPosixSystemStream(SystemStream stream) { return JnaNativePty.isPosixSystemStream(stream); } @Override - public String systemStreamName(Stream stream) { + public String systemStreamName(SystemStream stream) { if (OSUtils.IS_WINDOWS) { return null; } else { return JnaNativePty.posixSystemStreamName(stream); } } + + @Override + public int systemStreamWidth(SystemStream stream) { + try (Pty pty = current(stream)) { + return pty.getSize().getColumns(); + } catch (Throwable t) { + return -1; + } + } } diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/freebsd/FreeBsdNativePty.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/freebsd/FreeBsdNativePty.java index b3a84f239..847102349 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/freebsd/FreeBsdNativePty.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/freebsd/FreeBsdNativePty.java @@ -14,6 +14,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jna.JnaNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import com.sun.jna.LastErrorException; @@ -38,18 +39,20 @@ void openpty(int[] master, int[] slave, byte[] name, CLibrary.termios t, CLibrar UtilLibrary INSTANCE = Native.load("util", UtilLibrary.class); } - public static FreeBsdNativePty current(TerminalProvider.Stream consoleStream) throws IOException { - switch (consoleStream) { + public static FreeBsdNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { + switch (systemStream) { case Output: - return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); + return new FreeBsdNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); case Error: - return new FreeBsdNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); + return new FreeBsdNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } - public static FreeBsdNativePty open(Attributes attr, Size size) throws IOException { + public static FreeBsdNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -60,14 +63,24 @@ public static FreeBsdNativePty open(Attributes attr, Size size) throws IOExcepti len++; } String name = new String(buf, 0, len); - return new FreeBsdNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new FreeBsdNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public FreeBsdNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public FreeBsdNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public FreeBsdNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -75,7 +88,7 @@ public FreeBsdNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } @Override diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/linux/LinuxNativePty.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/linux/LinuxNativePty.java index 471359770..195a6e366 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/linux/LinuxNativePty.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/linux/LinuxNativePty.java @@ -14,6 +14,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jna.JnaNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import com.sun.jna.LastErrorException; @@ -38,18 +39,20 @@ void openpty(int[] master, int[] slave, byte[] name, CLibrary.termios t, CLibrar UtilLibrary INSTANCE = Native.load("util", UtilLibrary.class); } - public static LinuxNativePty current(TerminalProvider.Stream consoleStream) throws IOException { - switch (consoleStream) { + public static LinuxNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { + switch (systemStream) { case Output: - return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); + return new LinuxNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); case Error: - return new LinuxNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); + return new LinuxNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } - public static LinuxNativePty open(Attributes attr, Size size) throws IOException { + public static LinuxNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -60,14 +63,24 @@ public static LinuxNativePty open(Attributes attr, Size size) throws IOException len++; } String name = new String(buf, 0, len); - return new LinuxNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new LinuxNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public LinuxNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public LinuxNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public LinuxNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -75,7 +88,7 @@ public LinuxNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } @Override diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/osx/OsXNativePty.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/osx/OsXNativePty.java index 28b73c544..50c692575 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/osx/OsXNativePty.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/osx/OsXNativePty.java @@ -14,6 +14,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jna.JnaNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import com.sun.jna.Native; @@ -30,18 +31,20 @@ public class OsXNativePty extends JnaNativePty { private static final CLibrary C_LIBRARY = Native.load(Platform.C_LIBRARY_NAME, CLibrary.class); - public static OsXNativePty current(TerminalProvider.Stream consoleStream) throws IOException { - switch (consoleStream) { + public static OsXNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { + switch (systemStream) { case Output: - return new OsXNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); + return new OsXNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); case Error: - return new OsXNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); + return new OsXNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } - public static OsXNativePty open(Attributes attr, Size size) throws IOException { + public static OsXNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -52,14 +55,24 @@ public static OsXNativePty open(Attributes attr, Size size) throws IOException { len++; } String name = new String(buf, 0, len); - return new OsXNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new OsXNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public OsXNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public OsXNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public OsXNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -67,7 +80,7 @@ public OsXNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } @Override diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/solaris/SolarisNativePty.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/solaris/SolarisNativePty.java index 52986cc49..7d4cf3466 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/solaris/SolarisNativePty.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/solaris/SolarisNativePty.java @@ -14,6 +14,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.impl.jna.JnaNativePty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import com.sun.jna.Native; @@ -29,18 +30,20 @@ public class SolarisNativePty extends JnaNativePty { private static final CLibrary C_LIBRARY = Native.load(Platform.C_LIBRARY_NAME, CLibrary.class); - public static SolarisNativePty current(TerminalProvider.Stream consoleStream) throws IOException { - switch (consoleStream) { + public static SolarisNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException { + switch (systemStream) { case Output: - return new SolarisNativePty(-1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); + return new SolarisNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(0)); case Error: - return new SolarisNativePty(-1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); + return new SolarisNativePty( + provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(0)); default: - throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupport stream for console: " + systemStream); } } - public static SolarisNativePty open(Attributes attr, Size size) throws IOException { + public static SolarisNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException { int[] master = new int[1]; int[] slave = new int[1]; byte[] buf = new byte[64]; @@ -51,14 +54,24 @@ public static SolarisNativePty open(Attributes attr, Size size) throws IOExcepti len++; } String name = new String(buf, 0, len); - return new SolarisNativePty(master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); + return new SolarisNativePty( + provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name); } - public SolarisNativePty(int master, FileDescriptor masterFD, int slave, FileDescriptor slaveFD, String name) { - super(master, masterFD, slave, slaveFD, name); + public SolarisNativePty( + TerminalProvider provider, + SystemStream systemStream, + int master, + FileDescriptor masterFD, + int slave, + FileDescriptor slaveFD, + String name) { + super(provider, systemStream, master, masterFD, slave, slaveFD, name); } public SolarisNativePty( + TerminalProvider provider, + SystemStream systemStream, int master, FileDescriptor masterFD, int slave, @@ -66,7 +79,7 @@ public SolarisNativePty( int slaveOut, FileDescriptor slaveOutFD, String name) { - super(master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); + super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name); } @Override diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java index f8b26f690..97830cd1f 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java @@ -17,6 +17,7 @@ import org.jline.terminal.Cursor; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractWindowsTerminal; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.InfoCmp.Capability; import org.jline.utils.OSUtils; @@ -32,21 +33,22 @@ public class JnaWinSysTerminal extends AbstractWindowsTerminal { private static final Pointer consoleErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE); public static JnaWinSysTerminal createTerminal( + TerminalProvider provider, + SystemStream systemStream, String name, String type, boolean ansiPassThrough, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, - boolean paused, - TerminalProvider.Stream consoleStream) + boolean paused) throws IOException { // Get input console mode IntByReference inMode = new IntByReference(); Kernel32.INSTANCE.GetConsoleMode(JnaWinSysTerminal.consoleIn, inMode); // Get output console and mode Pointer console; - switch (consoleStream) { + switch (systemStream) { case Output: console = JnaWinSysTerminal.consoleOut; break; @@ -54,7 +56,7 @@ public static JnaWinSysTerminal createTerminal( console = JnaWinSysTerminal.consoleErr; break; default: - throw new IllegalArgumentException("Unsupported stream for console: " + consoleStream); + throw new IllegalArgumentException("Unsupported stream for console: " + systemStream); } IntByReference outMode = new IntByReference(); Kernel32.INSTANCE.GetConsoleMode(console, outMode); @@ -77,6 +79,8 @@ public static JnaWinSysTerminal createTerminal( } // Create terminal JnaWinSysTerminal terminal = new JnaWinSysTerminal( + provider, + systemStream, writer, name, type, @@ -104,7 +108,7 @@ private static boolean enableVtp(Pointer console, int outMode) { } } - public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { + public static boolean isWindowsSystemStream(SystemStream stream) { try { IntByReference mode = new IntByReference(); Pointer console; @@ -129,6 +133,8 @@ public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { } JnaWinSysTerminal( + TerminalProvider provider, + SystemStream systemStream, Writer writer, String name, String type, @@ -141,6 +147,8 @@ public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) { int outConsoleMode) throws IOException { super( + provider, + systemStream, writer, name, type, diff --git a/terminal-jna/src/test/java/org/jline/terminal/impl/jna/JnaNativePtyTest.java b/terminal-jna/src/test/java/org/jline/terminal/impl/jna/JnaNativePtyTest.java index 4338f040f..61a3855f6 100644 --- a/terminal-jna/src/test/java/org/jline/terminal/impl/jna/JnaNativePtyTest.java +++ b/terminal-jna/src/test/java/org/jline/terminal/impl/jna/JnaNativePtyTest.java @@ -27,7 +27,7 @@ public void testOpen() throws IOException { // currently disabled on Mac M1 silicon assumeFalse(Platform.isMac() && Platform.is64Bit() && Platform.isARM()); assumeFalse(Platform.isWindows()); - JnaNativePty pty = JnaNativePty.open(null, null); + JnaNativePty pty = JnaNativePty.open(null, null, null); assertNotNull(pty); Size sz = pty.getSize(); assertNotNull(sz); diff --git a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java index d1fdae166..32993ba98 100644 --- a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java +++ b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java @@ -33,6 +33,7 @@ import org.jline.terminal.impl.AbstractPosixTerminal; import org.jline.terminal.impl.AbstractTerminal; import org.jline.terminal.impl.DumbTerminal; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.Log; import org.jline.utils.OSUtils; @@ -136,6 +137,7 @@ public static TerminalBuilder builder() { private int codepage; private Boolean system; private SystemOutput systemOutput; + private String providers; private Boolean jna; private Boolean jansi; private Boolean exec; @@ -180,6 +182,11 @@ public TerminalBuilder systemOutput(SystemOutput systemOutput) { return this; } + public TerminalBuilder providers(String providers) { + this.providers = providers; + return this; + } + public TerminalBuilder jna(boolean jna) { this.jna = jna; return this; @@ -397,7 +404,7 @@ private Terminal doBuild() throws IOException { if (ffm) { try { TerminalProvider provider = TerminalProvider.load("ffm"); - provider.isSystemStream(TerminalProvider.Stream.Output); + provider.isSystemStream(SystemStream.Output); providers.add(provider); } catch (Throwable t) { Log.debug("Unable to load FFM support: ", t); @@ -407,7 +414,7 @@ private Terminal doBuild() throws IOException { if (jna) { try { TerminalProvider provider = TerminalProvider.load("jna"); - provider.isSystemStream(TerminalProvider.Stream.Output); + provider.isSystemStream(SystemStream.Output); providers.add(provider); } catch (Throwable t) { Log.debug("Unable to load JNA support: ", t); @@ -417,7 +424,7 @@ private Terminal doBuild() throws IOException { if (jansi) { try { TerminalProvider provider = TerminalProvider.load("jansi"); - provider.isSystemStream(TerminalProvider.Stream.Output); + provider.isSystemStream(SystemStream.Output); providers.add(provider); } catch (Throwable t) { Log.debug("Unable to load JANSI support: ", t); @@ -434,7 +441,8 @@ private Terminal doBuild() throws IOException { } } List order = Arrays.asList( - System.getProperty(PROP_PROVIDERS, PROP_PROVIDERS_DEFAULT).split(",")); + (this.providers != null ? this.providers : System.getProperty(PROP_PROVIDERS, PROP_PROVIDERS_DEFAULT)) + .split(",")); providers.sort(Comparator.comparing(l -> { int idx = order.indexOf(l.name()); return idx >= 0 ? idx : Integer.MAX_VALUE; @@ -488,12 +496,12 @@ private Terminal doBuild() throws IOException { if (systemOutput == null) { systemOutput = SystemOutput.SysOutOrSysErr; } - Map system = Stream.of(TerminalProvider.Stream.values()) + Map system = Stream.of(SystemStream.values()) .collect(Collectors.toMap( stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream)))); - TerminalProvider.Stream console = select(system, systemOutput); + SystemStream systemStream = select(system, systemOutput); - if (system.get(TerminalProvider.Stream.Input) && console != null) { + if (system.get(SystemStream.Input) && systemStream != null) { if (attributes != null || size != null) { Log.warn("Attributes and size fields are ignored when creating a system terminal"); } @@ -517,7 +525,7 @@ private Terminal doBuild() throws IOException { nativeSignals, signalHandler, paused, - console); + systemStream); } catch (Throwable t) { Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t); exception.addSuppressed(t); @@ -570,12 +578,12 @@ private Terminal doBuild() throws IOException { } } if (color == null) { - color = console != null && System.getenv("TERM") != null; + color = systemStream != null && System.getenv("TERM") != null; } if (Log.isDebugEnabled()) { - Log.warn("input is tty: {}", system.get(TerminalProvider.Stream.Input)); - Log.warn("output is tty: {}", system.get(TerminalProvider.Stream.Output)); - Log.warn("error is tty: {}", system.get(TerminalProvider.Stream.Error)); + Log.warn("input is tty: {}", system.get(SystemStream.Input)); + Log.warn("output is tty: {}", system.get(SystemStream.Output)); + Log.warn("error is tty: {}", system.get(SystemStream.Error)); Log.warn("Creating a dumb terminal", exception); } else { Log.warn( @@ -591,9 +599,10 @@ private Terminal doBuild() throws IOException { color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB, new FileInputStream(FileDescriptor.in), new FileOutputStream( - console == TerminalProvider.Stream.Error ? FileDescriptor.err : FileDescriptor.out), + systemStream == SystemStream.Error ? FileDescriptor.err : FileDescriptor.out), encoding, - signalHandler); + signalHandler, + systemStream); } } else { for (TerminalProvider provider : providers) { @@ -614,23 +623,22 @@ private Terminal doBuild() throws IOException { return terminal; } - private TerminalProvider.Stream select(Map system, SystemOutput systemOutput) { + private SystemStream select(Map system, SystemOutput systemOutput) { switch (systemOutput) { case SysOut: - return select(system, TerminalProvider.Stream.Output); + return select(system, SystemStream.Output); case SysErr: - return select(system, TerminalProvider.Stream.Error); + return select(system, SystemStream.Error); case SysOutOrSysErr: - return select(system, TerminalProvider.Stream.Output, TerminalProvider.Stream.Error); + return select(system, SystemStream.Output, SystemStream.Error); case SysErrOrSysOut: - return select(system, TerminalProvider.Stream.Error, TerminalProvider.Stream.Output); + return select(system, SystemStream.Error, SystemStream.Output); } return null; } - private static TerminalProvider.Stream select( - Map system, TerminalProvider.Stream... streams) { - for (TerminalProvider.Stream s : streams) { + private static SystemStream select(Map system, SystemStream... streams) { + for (SystemStream s : streams) { if (system.get(s)) { return s; } diff --git a/terminal/src/main/java/org/jline/terminal/impl/AbstractPosixTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/AbstractPosixTerminal.java index b14b8e696..6d8649f72 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/AbstractPosixTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/AbstractPosixTerminal.java @@ -18,6 +18,8 @@ import org.jline.terminal.Cursor; import org.jline.terminal.Size; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; public abstract class AbstractPosixTerminal extends AbstractTerminal { @@ -82,4 +84,14 @@ protected void doClose() throws IOException { public Cursor getCursorPosition(IntConsumer discarded) { return CursorSupport.getCursorPosition(this, discarded); } + + @Override + public TerminalProvider getProvider() { + return getPty().getProvider(); + } + + @Override + public SystemStream getSystemStream() { + return getPty().getSystemStream(); + } } diff --git a/terminal/src/main/java/org/jline/terminal/impl/AbstractPty.java b/terminal/src/main/java/org/jline/terminal/impl/AbstractPty.java index 97cd05159..aeed6b3c6 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/AbstractPty.java +++ b/terminal/src/main/java/org/jline/terminal/impl/AbstractPty.java @@ -19,6 +19,8 @@ import org.jline.nativ.JLineNativeLoader; import org.jline.terminal.Attributes; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.NonBlockingInputStream; import static org.jline.terminal.TerminalBuilder.PROP_FILE_DESCRIPTOR_CREATION_MODE; @@ -29,8 +31,15 @@ public abstract class AbstractPty implements Pty { + protected final TerminalProvider provider; + protected final SystemStream systemStream; private Attributes current; + public AbstractPty(TerminalProvider provider, SystemStream systemStream) { + this.provider = provider; + this.systemStream = systemStream; + } + @Override public void setAttr(Attributes attr) throws IOException { current = new Attributes(attr); @@ -57,6 +66,16 @@ protected void checkInterrupted() throws InterruptedIOException { } } + @Override + public TerminalProvider getProvider() { + return provider; + } + + @Override + public SystemStream getSystemStream() { + return systemStream; + } + class PtyInputStream extends NonBlockingInputStream { final InputStream in; int c = 0; diff --git a/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java index 36dde577a..77598fcf7 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java @@ -27,7 +27,7 @@ import org.jline.terminal.Attributes.LocalFlag; import org.jline.terminal.Cursor; import org.jline.terminal.MouseEvent; -import org.jline.terminal.Terminal; +import org.jline.terminal.spi.TerminalExt; import org.jline.utils.ColorPalette; import org.jline.utils.Curses; import org.jline.utils.InfoCmp; @@ -35,7 +35,7 @@ import org.jline.utils.Log; import org.jline.utils.Status; -public abstract class AbstractTerminal implements Terminal { +public abstract class AbstractTerminal implements TerminalExt { protected final String name; protected final String type; diff --git a/terminal/src/main/java/org/jline/terminal/impl/AbstractWindowsTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/AbstractWindowsTerminal.java index bd5d77740..240c1d087 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/AbstractWindowsTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/AbstractWindowsTerminal.java @@ -19,6 +19,8 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.Curses; import org.jline.utils.InfoCmp; import org.jline.utils.Log; @@ -73,6 +75,8 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal protected final Console outConsole; protected final int originalInConsoleMode; protected final int originalOutConsoleMode; + private final TerminalProvider provider; + private final SystemStream systemStream; protected final Object lock = new Object(); protected boolean paused = true; @@ -84,6 +88,8 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal @SuppressWarnings("this-escape") public AbstractWindowsTerminal( + TerminalProvider provider, + SystemStream systemStream, Writer writer, String name, String type, @@ -96,6 +102,8 @@ public AbstractWindowsTerminal( int outConsoleMode) throws IOException { super(name, type, encoding, signalHandler); + this.provider = provider; + this.systemStream = systemStream; NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader(); this.slaveInputPipe = reader.getWriter(); this.reader = reader; @@ -523,4 +531,14 @@ public boolean trackMouse(MouseTracking tracking) { * @throws IOException if anything wrong happens */ protected abstract boolean processConsoleInput() throws IOException; + + @Override + public TerminalProvider getProvider() { + return provider; + } + + @Override + public SystemStream getSystemStream() { + return systemStream; + } } diff --git a/terminal/src/main/java/org/jline/terminal/impl/Diag.java b/terminal/src/main/java/org/jline/terminal/impl/Diag.java index 6bca5cc1b..b35e62555 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/Diag.java +++ b/terminal/src/main/java/org/jline/terminal/impl/Diag.java @@ -17,6 +17,7 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Terminal; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -94,16 +95,16 @@ static void diag(PrintStream out) { private static void testProvider(PrintStream out, TerminalProvider provider) { try { - out.println("StdIn stream = " + provider.isSystemStream(TerminalProvider.Stream.Input)); - out.println("StdOut stream = " + provider.isSystemStream(TerminalProvider.Stream.Output)); - out.println("StdErr stream = " + provider.isSystemStream(TerminalProvider.Stream.Error)); + out.println("StdIn stream = " + provider.isSystemStream(SystemStream.Input)); + out.println("StdOut stream = " + provider.isSystemStream(SystemStream.Output)); + out.println("StdErr stream = " + provider.isSystemStream(SystemStream.Error)); } catch (Throwable t2) { out.println("Unable to check stream: " + t2); } try { - out.println("StdIn stream name = " + provider.systemStreamName(TerminalProvider.Stream.Input)); - out.println("StdOut stream name = " + provider.systemStreamName(TerminalProvider.Stream.Output)); - out.println("StdErr stream name = " + provider.systemStreamName(TerminalProvider.Stream.Error)); + out.println("StdIn stream name = " + provider.systemStreamName(SystemStream.Input)); + out.println("StdOut stream name = " + provider.systemStreamName(SystemStream.Output)); + out.println("StdErr stream name = " + provider.systemStreamName(SystemStream.Error)); } catch (Throwable t2) { out.println("Unable to check stream names: " + t2); } @@ -115,7 +116,7 @@ private static void testProvider(PrintStream out, TerminalProvider provider) { false, Terminal.SignalHandler.SIG_DFL, false, - TerminalProvider.Stream.Output)) { + SystemStream.Output)) { if (terminal != null) { Attributes attr = terminal.enterRawMode(); try { diff --git a/terminal/src/main/java/org/jline/terminal/impl/DumbTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/DumbTerminal.java index a6006ffe2..354e167ad 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/DumbTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/DumbTerminal.java @@ -18,6 +18,8 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Attributes.ControlChar; import org.jline.terminal.Size; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.NonBlocking; import org.jline.utils.NonBlockingInputStream; import org.jline.utils.NonBlockingReader; @@ -30,6 +32,7 @@ public class DumbTerminal extends AbstractTerminal { private final PrintWriter writer; private final Attributes attributes; private final Size size; + private final SystemStream systemStream; public DumbTerminal(InputStream in, OutputStream out) throws IOException { this(TYPE_DUMB, TYPE_DUMB, in, out, null); @@ -37,12 +40,18 @@ public DumbTerminal(InputStream in, OutputStream out) throws IOException { public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding) throws IOException { - this(name, type, in, out, encoding, SignalHandler.SIG_DFL); + this(name, type, in, out, encoding, SignalHandler.SIG_DFL, null); } @SuppressWarnings("this-escape") public DumbTerminal( - String name, String type, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) + String name, + String type, + InputStream in, + OutputStream out, + Charset encoding, + SignalHandler signalHandler, + SystemStream systemStream) throws IOException { super(name, type, encoding, signalHandler); NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), in); @@ -89,6 +98,7 @@ public int read(long timeout, boolean isPeek) throws IOException { this.attributes.setControlChar(ControlChar.VKILL, (char) 21); this.attributes.setControlChar(ControlChar.VLNEXT, (char) 22); this.size = new Size(); + this.systemStream = systemStream; parseInfoCmp(); } @@ -127,4 +137,14 @@ public Size getSize() { public void setSize(Size sz) { size.copy(sz); } + + @Override + public TerminalProvider getProvider() { + return null; + } + + @Override + public SystemStream getSystemStream() { + return systemStream; + } } diff --git a/terminal/src/main/java/org/jline/terminal/impl/LineDisciplineTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/LineDisciplineTerminal.java index 56d39fd2c..7a60f2067 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/LineDisciplineTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/LineDisciplineTerminal.java @@ -24,6 +24,8 @@ import org.jline.terminal.Attributes.OutputFlag; import org.jline.terminal.Size; import org.jline.terminal.Terminal; +import org.jline.terminal.spi.SystemStream; +import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.NonBlocking; import org.jline.utils.NonBlockingPumpInputStream; import org.jline.utils.NonBlockingReader; @@ -310,6 +312,16 @@ protected void doClose() throws IOException { } } + @Override + public TerminalProvider getProvider() { + return null; + } + + @Override + public SystemStream getSystemStream() { + return null; + } + private class FilteringOutputStream extends OutputStream { @Override public void write(int b) throws IOException { diff --git a/terminal/src/main/java/org/jline/terminal/impl/ExecPty.java b/terminal/src/main/java/org/jline/terminal/impl/exec/ExecPty.java similarity index 88% rename from terminal/src/main/java/org/jline/terminal/impl/ExecPty.java rename to terminal/src/main/java/org/jline/terminal/impl/exec/ExecPty.java index 0202e64da..eb5c1b486 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/ExecPty.java +++ b/terminal/src/main/java/org/jline/terminal/impl/exec/ExecPty.java @@ -6,7 +6,7 @@ * * https://opensource.org/licenses/BSD-3-Clause */ -package org.jline.terminal.impl; +package org.jline.terminal.impl.exec; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -26,7 +26,9 @@ import org.jline.terminal.Attributes.LocalFlag; import org.jline.terminal.Attributes.OutputFlag; import org.jline.terminal.Size; +import org.jline.terminal.impl.AbstractPty; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; @@ -35,23 +37,22 @@ public class ExecPty extends AbstractPty implements Pty { private final String name; - private final TerminalProvider.Stream console; - public static Pty current(TerminalProvider.Stream console) throws IOException { + public static Pty current(TerminalProvider provider, SystemStream systemStream) throws IOException { try { String result = exec(true, OSUtils.TTY_COMMAND); - if (console != TerminalProvider.Stream.Output && console != TerminalProvider.Stream.Error) { - throw new IllegalArgumentException("console should be Output or Error: " + console); + if (systemStream != SystemStream.Output && systemStream != SystemStream.Error) { + throw new IllegalArgumentException("systemStream should be Output or Error: " + systemStream); } - return new ExecPty(result.trim(), console); + return new ExecPty(provider, systemStream, result.trim()); } catch (IOException e) { throw new IOException("Not a tty", e); } } - protected ExecPty(String name, TerminalProvider.Stream console) { + protected ExecPty(TerminalProvider provider, SystemStream systemStream, String name) { + super(provider, systemStream); this.name = name; - this.console = console; } @Override @@ -73,14 +74,14 @@ public OutputStream getMasterOutput() { @Override protected InputStream doGetSlaveInput() throws IOException { - return console != null ? new FileInputStream(FileDescriptor.in) : new FileInputStream(getName()); + return systemStream != null ? new FileInputStream(FileDescriptor.in) : new FileInputStream(getName()); } @Override public OutputStream getSlaveOutput() throws IOException { - return console == TerminalProvider.Stream.Output + return systemStream == SystemStream.Output ? new FileOutputStream(FileDescriptor.out) - : console == TerminalProvider.Stream.Error + : systemStream == SystemStream.Error ? new FileOutputStream(FileDescriptor.err) : new FileOutputStream(getName()); } @@ -96,11 +97,11 @@ protected void doSetAttr(Attributes attr) throws IOException { List commands = getFlagsToSet(attr, getAttr()); if (!commands.isEmpty()) { commands.add(0, OSUtils.STTY_COMMAND); - if (console == null) { + if (systemStream == null) { commands.add(1, OSUtils.STTY_F_OPTION); commands.add(2, getName()); } - exec(console != null, commands.toArray(new String[0])); + exec(systemStream != null, commands.toArray(new String[0])); } } @@ -160,12 +161,12 @@ public Size getSize() throws IOException { } protected String doGetConfig() throws IOException { - return console != null + return systemStream != null ? exec(true, OSUtils.STTY_COMMAND, "-a") : exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-a"); } - static Attributes doGetAttr(String cfg) throws IOException { + public static Attributes doGetAttr(String cfg) throws IOException { Attributes attributes = new Attributes(); for (InputFlag flag : InputFlag.values()) { Boolean value = doGetFlag(cfg, flag); @@ -270,7 +271,7 @@ static int doGetInt(String name, String cfg) throws IOException { @Override public void setSize(Size size) throws IOException { - if (console != null) { + if (systemStream != null) { exec( true, OSUtils.STTY_COMMAND, @@ -293,6 +294,6 @@ public void setSize(Size size) throws IOException { @Override public String toString() { - return "ExecPty[" + getName() + (console != null ? ", system]" : "]"); + return "ExecPty[" + getName() + (systemStream != null ? ", system]" : "]"); } } diff --git a/terminal/src/main/java/org/jline/terminal/impl/exec/ExecTerminalProvider.java b/terminal/src/main/java/org/jline/terminal/impl/exec/ExecTerminalProvider.java index 61b19cc77..35c1e3e3a 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/exec/ExecTerminalProvider.java +++ b/terminal/src/main/java/org/jline/terminal/impl/exec/ExecTerminalProvider.java @@ -21,10 +21,10 @@ import org.jline.terminal.Attributes; import org.jline.terminal.Size; import org.jline.terminal.Terminal; -import org.jline.terminal.impl.ExecPty; import org.jline.terminal.impl.ExternalTerminal; import org.jline.terminal.impl.PosixSysTerminal; import org.jline.terminal.spi.Pty; +import org.jline.terminal.spi.SystemStream; import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.ExecHelper; import org.jline.utils.Log; @@ -43,8 +43,8 @@ public String name() { return "exec"; } - public Pty current(Stream consoleStream) throws IOException { - return ExecPty.current(consoleStream); + public Pty current(SystemStream systemStream) throws IOException { + return ExecPty.current(this, systemStream); } @Override @@ -56,14 +56,14 @@ public Terminal sysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (OSUtils.IS_WINDOWS) { return winSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } else { return posixSysTerminal( - name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream); + name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream); } } @@ -75,10 +75,10 @@ public Terminal winSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) { - Pty pty = current(consoleStream); + Pty pty = current(systemStream); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler); } else { return null; @@ -93,9 +93,9 @@ public Terminal posixSysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException { - Pty pty = current(consoleStream); + Pty pty = current(systemStream); return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler); } @@ -115,7 +115,7 @@ public Terminal newTerminal( } @Override - public boolean isSystemStream(Stream stream) { + public boolean isSystemStream(SystemStream stream) { try { return isWindowsSystemStream(stream) || isPosixSystemStream(stream); } catch (Throwable t) { @@ -123,11 +123,11 @@ public boolean isSystemStream(Stream stream) { } } - public boolean isWindowsSystemStream(Stream stream) { + public boolean isWindowsSystemStream(SystemStream stream) { return systemStreamName(stream) != null; } - public boolean isPosixSystemStream(Stream stream) { + public boolean isPosixSystemStream(SystemStream stream) { try { Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal())) .inheritIO() @@ -140,11 +140,11 @@ public boolean isPosixSystemStream(Stream stream) { } @Override - public String systemStreamName(Stream stream) { + public String systemStreamName(SystemStream stream) { try { - ProcessBuilder.Redirect input = stream == Stream.Input + ProcessBuilder.Redirect input = stream == SystemStream.Input ? ProcessBuilder.Redirect.INHERIT - : newDescriptor(stream == Stream.Output ? FileDescriptor.out : FileDescriptor.err); + : newDescriptor(stream == SystemStream.Output ? FileDescriptor.out : FileDescriptor.err); Process p = new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start(); String result = ExecHelper.waitAndCapture(p); @@ -164,6 +164,15 @@ public String systemStreamName(Stream stream) { return null; } + @Override + public int systemStreamWidth(SystemStream stream) { + try (ExecPty pty = new ExecPty(this, stream, null)) { + return pty.getSize().getColumns(); + } catch (Throwable t) { + return -1; + } + } + private static RedirectPipeCreator redirectPipeCreator; protected static ProcessBuilder.Redirect newDescriptor(FileDescriptor fd) { diff --git a/terminal/src/main/java/org/jline/terminal/spi/Pty.java b/terminal/src/main/java/org/jline/terminal/spi/Pty.java index 607665ada..b8eda1fec 100644 --- a/terminal/src/main/java/org/jline/terminal/spi/Pty.java +++ b/terminal/src/main/java/org/jline/terminal/spi/Pty.java @@ -33,4 +33,8 @@ public interface Pty extends Closeable { Size getSize() throws IOException; void setSize(Size size) throws IOException; + + SystemStream getSystemStream(); + + TerminalProvider getProvider(); } diff --git a/terminal/src/main/java/org/jline/terminal/spi/SystemStream.java b/terminal/src/main/java/org/jline/terminal/spi/SystemStream.java new file mode 100644 index 000000000..51b284c27 --- /dev/null +++ b/terminal/src/main/java/org/jline/terminal/spi/SystemStream.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.terminal.spi; + +public enum SystemStream { + Input, + Output, + Error +} diff --git a/terminal/src/main/java/org/jline/terminal/spi/TerminalExt.java b/terminal/src/main/java/org/jline/terminal/spi/TerminalExt.java new file mode 100644 index 000000000..8c799388b --- /dev/null +++ b/terminal/src/main/java/org/jline/terminal/spi/TerminalExt.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, the original author(s). + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package org.jline.terminal.spi; + +import org.jline.terminal.Terminal; + +/** + * The {@code TerminalExt} interface is implemented by {@code Terminal}s + * and provides access to the Terminal's internals. + */ +public interface TerminalExt extends Terminal { + + /** + * Returns the {@code TerminalProvider} that created this terminal + * or {@code null} if the terminal was created with no provider. + */ + TerminalProvider getProvider(); + + /** + * The underlying system stream, may be {@link SystemStream#Output}, + * {@link SystemStream#Error}, or {@code null} if this terminal is not bound + * to a system stream. + */ + SystemStream getSystemStream(); +} diff --git a/terminal/src/main/java/org/jline/terminal/spi/TerminalProvider.java b/terminal/src/main/java/org/jline/terminal/spi/TerminalProvider.java index 0e721cb07..5e03677ed 100644 --- a/terminal/src/main/java/org/jline/terminal/spi/TerminalProvider.java +++ b/terminal/src/main/java/org/jline/terminal/spi/TerminalProvider.java @@ -20,12 +20,6 @@ public interface TerminalProvider { - enum Stream { - Input, - Output, - Error - } - String name(); Terminal sysTerminal( @@ -36,7 +30,7 @@ Terminal sysTerminal( boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, - Stream consoleStream) + SystemStream systemStream) throws IOException; Terminal newTerminal( @@ -51,9 +45,11 @@ Terminal newTerminal( Size size) throws IOException; - boolean isSystemStream(Stream stream); + boolean isSystemStream(SystemStream stream); + + String systemStreamName(SystemStream stream); - String systemStreamName(Stream stream); + int systemStreamWidth(SystemStream stream); static TerminalProvider load(String name) throws IOException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); diff --git a/terminal/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java b/terminal/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java index cb0962a44..c848f5de9 100644 --- a/terminal/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java +++ b/terminal/src/test/java/org/jline/terminal/impl/AbstractWindowsTerminalTest.java @@ -29,6 +29,8 @@ public void testWriterBuffering() throws Exception { StringWriter sw = new StringWriter(); Terminal terminal = new AbstractWindowsTerminal( + null, + null, new AnsiWriter(new BufferedWriter(sw)), "name", TYPE_WINDOWS, diff --git a/terminal/src/test/java/org/jline/terminal/impl/ExecPtyTest.java b/terminal/src/test/java/org/jline/terminal/impl/exec/ExecPtyTest.java similarity index 99% rename from terminal/src/test/java/org/jline/terminal/impl/ExecPtyTest.java rename to terminal/src/test/java/org/jline/terminal/impl/exec/ExecPtyTest.java index 238203dd8..a67165e0b 100644 --- a/terminal/src/test/java/org/jline/terminal/impl/ExecPtyTest.java +++ b/terminal/src/test/java/org/jline/terminal/impl/exec/ExecPtyTest.java @@ -6,7 +6,7 @@ * * https://opensource.org/licenses/BSD-3-Clause */ -package org.jline.terminal.impl; +package org.jline.terminal.impl.exec; import java.io.IOException; import java.util.EnumSet;