From 831116525793170e8fb77894763b4385ccf2d089 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 1 Mar 2024 07:57:04 +0100 Subject: [PATCH 1/3] Fixing the FffmTerminal to run on JDK 22 and on Linux. --- .github/workflows/master-build.yml | 2 +- jline/pom.xml | 7 +- pom.xml | 2 +- terminal-ffm/pom.xml | 11 +-- .../org/jline/terminal/impl/ffm/CLibrary.java | 73 ++++++++++++++----- .../impl/ffm/FfmTerminalProvider.java | 13 ++++ .../org/jline/terminal/impl/ffm/Kernel32.java | 12 +-- .../impl/ffm/NativeWinConsoleWriter.java | 3 +- .../impl/ffm/NativeWinSysTerminal.java | 1 - .../terminal/impl/ffm/WindowsAnsiWriter.java | 3 +- 10 files changed, 86 insertions(+), 41 deletions(-) diff --git a/.github/workflows/master-build.yml b/.github/workflows/master-build.yml index 1370df87a..7c2e954ac 100644 --- a/.github/workflows/master-build.yml +++ b/.github/workflows/master-build.yml @@ -31,7 +31,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest, ubuntu-20.04, windows-latest, macos-latest ] - java: [ '21' ] + java: [ '22' ] steps: - uses: actions/checkout@v2 diff --git a/jline/pom.xml b/jline/pom.xml index 6498b7634..4769c3fc3 100644 --- a/jline/pom.xml +++ b/jline/pom.xml @@ -400,7 +400,7 @@ - jdk21 + jdk22 compile @@ -408,11 +408,10 @@ **/ffm/*.java - 21 + 22 - -Xlint:all,-options,-preview + -Xlint:all,-options -Werror - --enable-preview diff --git a/pom.xml b/pom.xml index 162261352..8d953fbd0 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ UTF-8 2024-01-23T12:21:59Z - 21 + 22 8 3.6.3 diff --git a/terminal-ffm/pom.xml b/terminal-ffm/pom.xml index 3d0fad3d9..b6fc3450c 100644 --- a/terminal-ffm/pom.xml +++ b/terminal-ffm/pom.xml @@ -23,7 +23,7 @@ JLine FFM Terminal - 21 + 22 org.jline.terminal.ffm @@ -56,24 +56,21 @@ org.apache.maven.plugins maven-compiler-plugin - 21 - - --enable-preview - + ${java.release.version} org.apache.maven.plugins maven-surefire-plugin - --enable-preview --enable-native-access=ALL-UNNAMED + --enable-native-access=ALL-UNNAMED org.apache.maven.plugins maven-javadoc-plugin - --enable-preview --release ${java.release.version} + --release ${java.release.version} 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 ee2396e22..482af70ce 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 @@ -13,6 +13,8 @@ import java.io.InputStream; import java.lang.foreign.*; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.nio.file.Files; import java.nio.file.Path; @@ -33,7 +35,7 @@ import org.jline.terminal.spi.TerminalProvider; import org.jline.utils.OSUtils; -@SuppressWarnings("preview") +@SuppressWarnings("restricted") class CLibrary { private static final Logger logger = Logger.getLogger("org.jline"); @@ -51,8 +53,8 @@ static class winsize { ValueLayout.JAVA_SHORT.withName("ws_col"), ValueLayout.JAVA_SHORT, ValueLayout.JAVA_SHORT); - ws_row = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_row")); - ws_col = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("ws_col")); + ws_row = FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("ws_row")); + ws_col = FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("ws_col")); } private final java.lang.foreign.MemorySegment seg; @@ -97,24 +99,59 @@ static class termios { private static final VarHandle c_oflag; private static final VarHandle c_cflag; private static final VarHandle c_lflag; + private static final long c_cc_offset; private static final VarHandle c_ispeed; private static final VarHandle c_ospeed; static { - LAYOUT = MemoryLayout.structLayout( - ValueLayout.JAVA_LONG.withName("c_iflag"), - ValueLayout.JAVA_LONG.withName("c_oflag"), - ValueLayout.JAVA_LONG.withName("c_cflag"), - ValueLayout.JAVA_LONG.withName("c_lflag"), - MemoryLayout.sequenceLayout(32, ValueLayout.JAVA_BYTE).withName("c_cc"), - ValueLayout.JAVA_LONG.withName("c_ispeed"), - ValueLayout.JAVA_LONG.withName("c_ospeed")); - c_iflag = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_iflag")); - c_oflag = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_oflag")); - c_cflag = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_cflag")); - c_lflag = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_lflag")); - c_ispeed = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_ispeed")); - c_ospeed = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("c_ospeed")); + if (OSUtils.IS_OSX) { + LAYOUT = MemoryLayout.structLayout( + ValueLayout.JAVA_LONG.withName("c_iflag"), + ValueLayout.JAVA_LONG.withName("c_oflag"), + ValueLayout.JAVA_LONG.withName("c_cflag"), + ValueLayout.JAVA_LONG.withName("c_lflag"), + MemoryLayout.sequenceLayout(32, ValueLayout.JAVA_BYTE).withName("c_cc"), + ValueLayout.JAVA_LONG.withName("c_ispeed"), + ValueLayout.JAVA_LONG.withName("c_ospeed")); + } else if (OSUtils.IS_LINUX) { + LAYOUT = MemoryLayout.structLayout( + ValueLayout.JAVA_INT.withName("c_iflag"), + ValueLayout.JAVA_INT.withName("c_oflag"), + ValueLayout.JAVA_INT.withName("c_cflag"), + ValueLayout.JAVA_INT.withName("c_lflag"), + ValueLayout.JAVA_BYTE.withName("c_line"), + MemoryLayout.sequenceLayout(32, ValueLayout.JAVA_BYTE).withName("c_cc"), + MemoryLayout.paddingLayout(3), + ValueLayout.JAVA_INT.withName("c_ispeed"), + ValueLayout.JAVA_INT.withName("c_ospeed")); + } else { + throw new IllegalStateException("Unsupported system!"); + } + c_iflag = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_iflag"))); + c_oflag = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_oflag"))); + c_cflag = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_cflag"))); + c_lflag = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_lflag"))); + c_cc_offset = LAYOUT.byteOffset(MemoryLayout.PathElement.groupElement("c_cc")); + c_ispeed = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_ispeed"))); + c_ospeed = adjust2LinuxHandle( + FfmTerminalProvider.lookupVarHandle(LAYOUT, MemoryLayout.PathElement.groupElement("c_ospeed"))); + } + + private static VarHandle adjust2LinuxHandle(VarHandle v) { + if (OSUtils.IS_LINUX) { + MethodHandle id = MethodHandles.identity(int.class); + v = MethodHandles.filterValue( + v, + MethodHandles.explicitCastArguments(id, MethodType.methodType(int.class, long.class)), + MethodHandles.explicitCastArguments(id, MethodType.methodType(long.class, int.class))); + } + + return v; } private final java.lang.foreign.MemorySegment seg; @@ -259,7 +296,7 @@ void c_lflag(long f) { } java.lang.foreign.MemorySegment c_cc() { - return seg.asSlice(32, 20); + return seg.asSlice(c_cc_offset, 20); } long c_ispeed() { 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 828bd33af..1307ad8be 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 @@ -12,6 +12,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.nio.charset.Charset; import org.jline.terminal.Attributes; @@ -115,4 +119,13 @@ public int systemStreamWidth(SystemStream stream) { public String toString() { return "TerminalProvider[" + name() + "]"; } + + static VarHandle lookupVarHandle(MemoryLayout layout, PathElement... element) { + VarHandle h = layout.varHandle(element); + + // the last parameter of the VarHandle is additional offset, hardcode zero: + h = MethodHandles.insertCoordinates(h, 1, 0L); + + return h; + } } diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/Kernel32.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/Kernel32.java index 1a2d313d7..786dd897f 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/Kernel32.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/Kernel32.java @@ -14,7 +14,7 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; -@SuppressWarnings({"unused", "preview"}) +@SuppressWarnings({"unused", "restricted"}) final class Kernel32 { public static final int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; @@ -277,8 +277,8 @@ public static INPUT_RECORD[] readConsoleInputHelper(java.lang.foreign.MemorySegm public static INPUT_RECORD[] readConsoleInputHelper( java.lang.foreign.Arena arena, java.lang.foreign.MemorySegment handle, int count, boolean peek) throws IOException { - java.lang.foreign.MemorySegment inputRecordPtr = arena.allocateArray(INPUT_RECORD.LAYOUT, count); - java.lang.foreign.MemorySegment length = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT, 0); + java.lang.foreign.MemorySegment inputRecordPtr = arena.allocate(INPUT_RECORD.LAYOUT, count); + java.lang.foreign.MemorySegment length = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT, 1); int res = peek ? PeekConsoleInputW(handle, inputRecordPtr, count, length) : ReadConsoleInputW(handle, inputRecordPtr, count, length); @@ -910,11 +910,13 @@ static T requireNonNull(T obj, String symbolName) { } static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String name) { - return layout.varHandle(java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); + return FfmTerminalProvider.lookupVarHandle( + layout, java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); } static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String e1, String name) { - return layout.varHandle( + return FfmTerminalProvider.lookupVarHandle( + layout, java.lang.foreign.MemoryLayout.PathElement.groupElement(e1), java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); } diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinConsoleWriter.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinConsoleWriter.java index 38573f954..2cc82ba6b 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinConsoleWriter.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/NativeWinConsoleWriter.java @@ -19,7 +19,6 @@ import static org.jline.terminal.impl.ffm.Kernel32.WriteConsoleW; import static org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage; -@SuppressWarnings("preview") class NativeWinConsoleWriter extends AbstractWindowsConsoleWriter { private final java.lang.foreign.MemorySegment console = GetStdHandle(STD_OUTPUT_HANDLE); @@ -27,7 +26,7 @@ class NativeWinConsoleWriter extends AbstractWindowsConsoleWriter { @Override protected void writeConsole(char[] text, int len) throws IOException { try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) { - java.lang.foreign.MemorySegment txt = arena.allocateArray(ValueLayout.JAVA_CHAR, text); + java.lang.foreign.MemorySegment txt = arena.allocateFrom(ValueLayout.JAVA_CHAR, text); if (WriteConsoleW(console, txt, len, MemorySegment.NULL, MemorySegment.NULL) == 0) { throw new IOException("Failed to write to console: " + getLastErrorMessage()); } 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 2a2548f72..89220e6b9 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 @@ -38,7 +38,6 @@ import static org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage; import static org.jline.terminal.impl.ffm.Kernel32.readConsoleInputHelper; -@SuppressWarnings("preview") public class NativeWinSysTerminal extends AbstractWindowsTerminal { public static NativeWinSysTerminal createTerminal( diff --git a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/WindowsAnsiWriter.java b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/WindowsAnsiWriter.java index ea6b89d67..5bd69fb2a 100644 --- a/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/WindowsAnsiWriter.java +++ b/terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/WindowsAnsiWriter.java @@ -37,7 +37,6 @@ import static org.jline.terminal.impl.ffm.Kernel32.SetConsoleTitleW; import static org.jline.terminal.impl.ffm.Kernel32.getLastErrorMessage; -@SuppressWarnings("preview") class WindowsAnsiWriter extends AnsiWriter { private static final java.lang.foreign.MemorySegment console = GetStdHandle(STD_OUTPUT_HANDLE); @@ -401,7 +400,7 @@ protected void processDeleteLine(int optionInt) throws IOException { @Override protected void processChangeWindowTitle(String title) { try (java.lang.foreign.Arena session = java.lang.foreign.Arena.ofConfined()) { - java.lang.foreign.MemorySegment str = session.allocateUtf8String(title); + java.lang.foreign.MemorySegment str = session.allocateFrom(title); SetConsoleTitleW(str); } } From bbe3c2a991deb32069cf7ef3b703ee69b8109598 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 6 Mar 2024 10:38:12 +0100 Subject: [PATCH 2/3] Ensuring control characters are not re-written inadvertedly. --- .../org/jline/terminal/impl/ffm/CLibrary.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) 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 482af70ce..f3ce3c1f1 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 @@ -248,14 +248,18 @@ private static VarHandle adjust2LinuxHandle(VarHandle v) { c_cc[VINTR] = (byte) t.getControlChar(Attributes.ControlChar.VINTR); c_cc[VQUIT] = (byte) t.getControlChar(Attributes.ControlChar.VQUIT); c_cc[VSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VSUSP); - c_cc[VDSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VDSUSP); + if (VDSUSP != (-1)) { + c_cc[VDSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VDSUSP); + } c_cc[VSTART] = (byte) t.getControlChar(Attributes.ControlChar.VSTART); c_cc[VSTOP] = (byte) t.getControlChar(Attributes.ControlChar.VSTOP); c_cc[VLNEXT] = (byte) t.getControlChar(Attributes.ControlChar.VLNEXT); c_cc[VDISCARD] = (byte) t.getControlChar(Attributes.ControlChar.VDISCARD); c_cc[VMIN] = (byte) t.getControlChar(Attributes.ControlChar.VMIN); c_cc[VTIME] = (byte) t.getControlChar(Attributes.ControlChar.VTIME); - c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS); + if (VSTATUS != (-1)) { + c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS); + } c_cc().copyFrom(java.lang.foreign.MemorySegment.ofArray(c_cc)); } @@ -414,14 +418,18 @@ public Attributes asAttributes() { cc.put(Attributes.ControlChar.VINTR, (int) c_cc[VINTR]); cc.put(Attributes.ControlChar.VQUIT, (int) c_cc[VQUIT]); cc.put(Attributes.ControlChar.VSUSP, (int) c_cc[VSUSP]); - cc.put(Attributes.ControlChar.VDSUSP, (int) c_cc[VDSUSP]); + if (VDSUSP != (-1)) { + cc.put(Attributes.ControlChar.VDSUSP, (int) c_cc[VDSUSP]); + } cc.put(Attributes.ControlChar.VSTART, (int) c_cc[VSTART]); cc.put(Attributes.ControlChar.VSTOP, (int) c_cc[VSTOP]); cc.put(Attributes.ControlChar.VLNEXT, (int) c_cc[VLNEXT]); cc.put(Attributes.ControlChar.VDISCARD, (int) c_cc[VDISCARD]); cc.put(Attributes.ControlChar.VMIN, (int) c_cc[VMIN]); cc.put(Attributes.ControlChar.VTIME, (int) c_cc[VTIME]); - cc.put(Attributes.ControlChar.VSTATUS, (int) c_cc[VSTATUS]); + if (VSTATUS != (-1)) { + cc.put(Attributes.ControlChar.VSTATUS, (int) c_cc[VSTATUS]); + } // Return return attr; } @@ -667,19 +675,19 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { private static final int VWERASE; private static final int VKILL; private static final int VREPRINT; - private static int VERASE2; + private static final int VERASE2; private static final int VINTR; private static final int VQUIT; private static final int VSUSP; - private static int VDSUSP; + private static final int VDSUSP; private static final int VSTART; private static final int VSTOP; private static final int VLNEXT; private static final int VDISCARD; private static final int VMIN; - private static int VSWTC; + private static final int VSWTC; private static final int VTIME; - private static int VSTATUS; + private static final int VSTATUS; private static final int IGNBRK; private static final int BRKINT; @@ -821,6 +829,9 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { VWERASE = 14; VLNEXT = 15; VEOL2 = 16; + VERASE2 = -1; + VDSUSP = -1; + VSTATUS = -1; IGNBRK = 0x0000001; BRKINT = 0x0000002; @@ -943,6 +954,9 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { VWERASE = 14; VLNEXT = 15; VEOL2 = 16; + VERASE2 = -1; + VDSUSP = -1; + VSTATUS = -1; IGNBRK = 0x0000001; BRKINT = 0x0000002; @@ -1063,6 +1077,8 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { VMIN = 16; VTIME = 17; VSTATUS = 18; + VERASE2 = -1; + VSWTC = -1; IGNBRK = 0x00000001; BRKINT = 0x00000002; @@ -1156,6 +1172,7 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) { VMIN = 16; VTIME = 17; VSTATUS = 18; + VSWTC = -1; IGNBRK = 0x0000001; BRKINT = 0x0000002; From 69813aff1266e4cc5e594449695cac05f9baa9c9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 7 Mar 2024 21:45:18 +0100 Subject: [PATCH 3/3] Update terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java Co-authored-by: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> --- .../java/org/jline/terminal/impl/ffm/FfmTerminalProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1307ad8be..4ea0579d9 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 @@ -124,7 +124,7 @@ static VarHandle lookupVarHandle(MemoryLayout layout, PathElement... element) { VarHandle h = layout.varHandle(element); // the last parameter of the VarHandle is additional offset, hardcode zero: - h = MethodHandles.insertCoordinates(h, 1, 0L); + h = MethodHandles.insertCoordinates(h, h.coordinateTypes().size() - 1, 0L); return h; }