diff --git a/src/main/cpp/posixFunctions.c b/src/main/cpp/posixFunctions.c index 7ac27d0..32c7d19 100644 --- a/src/main/cpp/posixFunctions.c +++ b/src/main/cpp/posixFunctions.c @@ -3,6 +3,7 @@ #include #include #include +#include void markFailed(JNIEnv *env, jobject result) { jclass destClass = env->GetObjectClass(result); @@ -48,3 +49,18 @@ Java_net_rubygrapefruit_platform_internal_PosixTerminalFunctions_isatty(JNIEnv * return JNI_FALSE; } } + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_PosixTerminalFunctions_getTerminalSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) { + struct winsize screen_size; + int retval = ioctl(output+1, TIOCGWINSZ, &screen_size); + if (retval != 0) { + markFailed(env, result); + return; + } + jclass dimensionClass = env->GetObjectClass(dimension); + jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I"); + env->SetIntField(dimension, widthField, screen_size.ws_col); + jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I"); + env->SetIntField(dimension, heightField, screen_size.ws_row); +} diff --git a/src/main/java/net/rubygrapefruit/platform/Main.java b/src/main/java/net/rubygrapefruit/platform/Main.java index 61c117d..48f3b30 100644 --- a/src/main/java/net/rubygrapefruit/platform/Main.java +++ b/src/main/java/net/rubygrapefruit/platform/Main.java @@ -1,11 +1,21 @@ package net.rubygrapefruit.platform; +import java.awt.*; + public class Main { public static void main(String[] args) { Process process = Platform.get(Process.class); System.out.println("* PID: " + process.getPid()); + Terminal terminal = Platform.get(Terminal.class); - System.out.println("* stdout: " + (terminal.isTerminal(Terminal.Output.Stdout) ? "terminal" : "not a terminal")); - System.out.println("* stderr: " + (terminal.isTerminal(Terminal.Output.Stderr) ? "terminal" : "not a terminal")); + + boolean stdoutIsTerminal = terminal.isTerminal(Terminal.Output.Stdout); + boolean stderrIsTerminal = terminal.isTerminal(Terminal.Output.Stderr); + System.out.println("* stdout: " + (stdoutIsTerminal ? "terminal" : "not a terminal")); + System.out.println("* stderr: " + (stderrIsTerminal ? "terminal" : "not a terminal")); + if (stdoutIsTerminal) { + TerminalSize terminalSize = terminal.getTerminalSize(Terminal.Output.Stdout); + System.out.println("* terminal size: " + terminalSize.getCols() + " cols x " + terminalSize.getRows() + " rows"); + } } } diff --git a/src/main/java/net/rubygrapefruit/platform/Platform.java b/src/main/java/net/rubygrapefruit/platform/Platform.java index 92c681a..5416750 100644 --- a/src/main/java/net/rubygrapefruit/platform/Platform.java +++ b/src/main/java/net/rubygrapefruit/platform/Platform.java @@ -31,12 +31,7 @@ public class Platform { return type.cast(new DefaultProcess()); } if (type.equals(Terminal.class)) { - return type.cast(new Terminal(){ - @Override - public boolean isTerminal(Output output) { - return PosixTerminalFunctions.isatty(output.ordinal()); - } - }); + return type.cast(new DefaultTerminal()); } throw new UnsupportedOperationException(String.format("Cannot load unknown native integration %s.", type.getName())); @@ -70,4 +65,22 @@ public class Platform { return PosixProcessFunctions.getPid(); } } + + private static class DefaultTerminal implements Terminal { + @Override + public boolean isTerminal(Output output) { + return PosixTerminalFunctions.isatty(output.ordinal()); + } + + @Override + public TerminalSize getTerminalSize(Output output) { + MutableTerminalSize terminalSize = new MutableTerminalSize(); + FunctionResult result = new FunctionResult(); + PosixTerminalFunctions.getTerminalSize(output.ordinal(), terminalSize, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not get terminal size. Errno is %d.", result.getErrno())); + } + return terminalSize; + } + } } diff --git a/src/main/java/net/rubygrapefruit/platform/Terminal.java b/src/main/java/net/rubygrapefruit/platform/Terminal.java index bbdb17b..2adf593 100644 --- a/src/main/java/net/rubygrapefruit/platform/Terminal.java +++ b/src/main/java/net/rubygrapefruit/platform/Terminal.java @@ -4,4 +4,6 @@ public interface Terminal extends NativeIntegration { enum Output {Stdout, Stderr} boolean isTerminal(Output output); + + TerminalSize getTerminalSize(Output output); } diff --git a/src/main/java/net/rubygrapefruit/platform/TerminalSize.java b/src/main/java/net/rubygrapefruit/platform/TerminalSize.java new file mode 100644 index 0000000..99ce742 --- /dev/null +++ b/src/main/java/net/rubygrapefruit/platform/TerminalSize.java @@ -0,0 +1,7 @@ +package net.rubygrapefruit.platform; + +public interface TerminalSize { + public int getCols(); + + public int getRows(); +} diff --git a/src/main/java/net/rubygrapefruit/platform/internal/MutableTerminalSize.java b/src/main/java/net/rubygrapefruit/platform/internal/MutableTerminalSize.java new file mode 100644 index 0000000..f075266 --- /dev/null +++ b/src/main/java/net/rubygrapefruit/platform/internal/MutableTerminalSize.java @@ -0,0 +1,16 @@ +package net.rubygrapefruit.platform.internal; + +import net.rubygrapefruit.platform.TerminalSize; + +public class MutableTerminalSize implements TerminalSize { + int rows; + int cols; + + public int getCols() { + return cols; + } + + public int getRows() { + return rows; + } +} diff --git a/src/main/java/net/rubygrapefruit/platform/internal/PosixTerminalFunctions.java b/src/main/java/net/rubygrapefruit/platform/internal/PosixTerminalFunctions.java index 15d89e2..e092c85 100644 --- a/src/main/java/net/rubygrapefruit/platform/internal/PosixTerminalFunctions.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/PosixTerminalFunctions.java @@ -1,5 +1,7 @@ package net.rubygrapefruit.platform.internal; public class PosixTerminalFunctions { - public static native boolean isatty(int fildes); + public static native boolean isatty(int filedes); + + public static native void getTerminalSize(int filedes, MutableTerminalSize size, FunctionResult result); } diff --git a/src/test/groovy/net/rubygrapefruit/platform/TerminalTest.groovy b/src/test/groovy/net/rubygrapefruit/platform/TerminalTest.groovy index f3231ad..8b1f7f0 100644 --- a/src/test/groovy/net/rubygrapefruit/platform/TerminalTest.groovy +++ b/src/test/groovy/net/rubygrapefruit/platform/TerminalTest.groovy @@ -13,4 +13,13 @@ class TerminalTest extends Specification { !terminal.isTerminal(Terminal.Output.Stdout); !terminal.isTerminal(Terminal.Output.Stderr); } + + def "cannot detemine terminal size from a test"() { + when: + terminal.getTerminalSize(Terminal.Output.Stdout) + + then: + NativeException e = thrown() + e.message == 'Could not get terminal size. Errno is 25.' + } }