Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the message when a provider cannot be used by doing an early check and restore compatibility with Jansi 1.17 (fixes #904) #906

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.regex.Pattern;

import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.internal.Kernel32;
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
Expand Down Expand Up @@ -79,6 +80,20 @@ public static boolean isAtLeast(int major, int minor) {
return JANSI_MAJOR_VERSION > major || JANSI_MAJOR_VERSION == major && JANSI_MINOR_VERSION >= minor;
}

public static void verifyAtLeast(int major, int minor) {
if (!isAtLeast(major, minor)) {
throw new UnsupportedOperationException("An old version of Jansi is loaded from "
+ Kernel32.class
.getClassLoader()
.getResource(Kernel32.class.getName().replace('.', '/') + ".class"));
}
}

public JansiTerminalProvider() {
verifyAtLeast(1, 17);
checkIsSystemStream(SystemStream.Output);
}

@Override
public String name() {
return TerminalBuilder.PROP_PROVIDER_JANSI;
Expand All @@ -93,29 +108,29 @@ public Pty current(SystemStream systemStream) throws IOException {
} else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
// Solaris is not supported by jansi
// return SolarisNativePty.current();
throw new UnsupportedOperationException("Unsupported platform " + osName);
} else if (osName.startsWith("FreeBSD")) {
if (isAtLeast(1, 16)) {
return FreeBsdNativePty.current(this, systemStream);
}
return FreeBsdNativePty.current(this, systemStream);
} else {
throw new UnsupportedOperationException("Unsupported platform " + osName);
}
throw new UnsupportedOperationException();
}

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(this, attributes, size);
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
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(this, attributes, size);
}
String osName = System.getProperty("os.name");
if (osName.startsWith("Linux")) {
return LinuxNativePty.open(this, attributes, size);
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
return OsXNativePty.open(this, attributes, size);
} else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
// Solaris is not supported by jansi
// return SolarisNativePty.current();
throw new UnsupportedOperationException("Unsupported platform " + osName);
} else if (osName.startsWith("FreeBSD")) {
return FreeBsdNativePty.open(this, attributes, size);
} else {
throw new UnsupportedOperationException("Unsupported platform " + osName);
}
throw new UnsupportedOperationException();
}

@Override
Expand Down Expand Up @@ -148,15 +163,10 @@ public Terminal winSysTerminal(
boolean paused,
SystemStream systemStream)
throws IOException {
if (isAtLeast(1, 12)) {
JansiWinSysTerminal terminal = JansiWinSysTerminal.createTerminal(
this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused);
if (!isAtLeast(1, 16)) {
terminal.disableScrolling();
}
return terminal;
}
throw new UnsupportedOperationException();
JansiWinSysTerminal terminal = JansiWinSysTerminal.createTerminal(
this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused);
terminal.disableScrolling();
return terminal;
}

public Terminal posixSysTerminal(
Expand Down Expand Up @@ -192,22 +202,18 @@ public Terminal newTerminal(
@Override
public boolean isSystemStream(SystemStream stream) {
try {
if (OSUtils.IS_WINDOWS) {
return isWindowsSystemStream(stream);
} else {
return isPosixSystemStream(stream);
}
return checkIsSystemStream(stream);
} catch (Throwable t) {
return false;
}
}

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

public boolean isPosixSystemStream(SystemStream stream) {
return JansiNativePty.isPosixSystemStream(stream);
private boolean checkIsSystemStream(SystemStream stream) {
if (OSUtils.IS_WINDOWS) {
return JansiWinSysTerminal.isWindowsSystemStream(stream);
} else {
return JansiNativePty.isPosixSystemStream(stream);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@

import java.io.IOException;

import org.fusesource.jansi.internal.Kernel32;
import org.jline.terminal.impl.AbstractWindowsConsoleWriter;

import static org.fusesource.jansi.internal.Kernel32.WriteConsoleW;
import static org.jline.terminal.impl.jansi.win.WindowsSupport.getLastErrorMessage;

class JansiWinConsoleWriter extends AbstractWindowsConsoleWriter {

Expand All @@ -27,7 +27,7 @@ public JansiWinConsoleWriter(long console) {
@Override
protected void writeConsole(char[] text, int len) throws IOException {
if (WriteConsoleW(console, text, len, writtenChars, 0) == 0) {
throw new IOException("Failed to write to console: " + Kernel32.getLastErrorMessage());
throw new IOException("Failed to write to console: " + getLastErrorMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.function.IntConsumer;

import org.fusesource.jansi.internal.Kernel32;
Expand All @@ -28,17 +27,15 @@
import org.jline.utils.InfoCmp;
import org.jline.utils.OSUtils;

import static org.fusesource.jansi.internal.Kernel32.FORMAT_MESSAGE_FROM_SYSTEM;
import static org.fusesource.jansi.internal.Kernel32.FormatMessageW;
import static org.fusesource.jansi.internal.Kernel32.GetConsoleScreenBufferInfo;
import static org.fusesource.jansi.internal.Kernel32.GetLastError;
import static org.fusesource.jansi.internal.Kernel32.GetStdHandle;
import static org.fusesource.jansi.internal.Kernel32.INVALID_HANDLE_VALUE;
import static org.fusesource.jansi.internal.Kernel32.STD_ERROR_HANDLE;
import static org.fusesource.jansi.internal.Kernel32.STD_INPUT_HANDLE;
import static org.fusesource.jansi.internal.Kernel32.STD_OUTPUT_HANDLE;
import static org.fusesource.jansi.internal.Kernel32.WaitForSingleObject;
import static org.fusesource.jansi.internal.Kernel32.readConsoleInputHelper;
import static org.jline.terminal.impl.jansi.win.WindowsSupport.getLastErrorMessage;

public class JansiWinSysTerminal extends AbstractWindowsTerminal<Long> {

Expand Down Expand Up @@ -294,16 +291,4 @@ public void disableScrolling() {
strings.remove(InfoCmp.Capability.delete_line);
strings.remove(InfoCmp.Capability.parm_delete_line);
}

static String getLastErrorMessage() {
int errorCode = GetLastError();
return getErrorMessage(errorCode);
}

static String getErrorMessage(int errorCode) {
int bufferSize = 160;
byte[] data = new byte[bufferSize];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, bufferSize, null);
return new String(data, StandardCharsets.UTF_16LE).trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
import java.io.IOException;
import java.io.Writer;

import org.fusesource.jansi.internal.Kernel32;
import org.jline.utils.AnsiWriter;
import org.jline.utils.Colors;

import static org.fusesource.jansi.internal.Kernel32.*;
import static org.jline.terminal.impl.jansi.win.WindowsSupport.getLastErrorMessage;

/**
* A Windows ANSI escape processor, that uses JNA to access native platform
Expand Down Expand Up @@ -81,7 +81,7 @@ public WindowsAnsiWriter(Writer out) throws IOException {
private void getConsoleInfo() throws IOException {
out.flush();
if (GetConsoleScreenBufferInfo(console, info) == 0) {
throw new IOException("Could not get the screen info: " + Kernel32.getLastErrorMessage());
throw new IOException("Could not get the screen info: " + getLastErrorMessage());
}
if (negative) {
info.attributes = invertAttributeColors(info.attributes);
Expand All @@ -103,7 +103,7 @@ private void applyAttribute() throws IOException {
attributes = invertAttributeColors(attributes);
}
if (SetConsoleTextAttribute(console, attributes) == 0) {
throw new IOException(Kernel32.getLastErrorMessage());
throw new IOException(getLastErrorMessage());
}
}

Expand All @@ -121,7 +121,7 @@ private void applyCursorPosition() throws IOException {
info.cursorPosition.x = (short) Math.max(0, Math.min(info.size.x - 1, info.cursorPosition.x));
info.cursorPosition.y = (short) Math.max(0, Math.min(info.size.y - 1, info.cursorPosition.y));
if (SetConsoleCursorPosition(console, info.cursorPosition.copy()) == 0) {
throw new IOException(Kernel32.getLastErrorMessage());
throw new IOException(getLastErrorMessage());
}
}

Expand Down Expand Up @@ -359,7 +359,7 @@ protected void processInsertLine(int optionInt) throws IOException {
info.attributes = originalColors;
info.unicodeChar = ' ';
if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
throw new IOException(Kernel32.getLastErrorMessage());
throw new IOException(getLastErrorMessage());
}
}

Expand All @@ -375,7 +375,7 @@ protected void processDeleteLine(int optionInt) throws IOException {
info.attributes = originalColors;
info.unicodeChar = ' ';
if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
throw new IOException(Kernel32.getLastErrorMessage());
throw new IOException(getLastErrorMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.impl.jansi.win;

import java.nio.charset.StandardCharsets;

import static org.fusesource.jansi.internal.Kernel32.FORMAT_MESSAGE_FROM_SYSTEM;
import static org.fusesource.jansi.internal.Kernel32.FormatMessageW;
import static org.fusesource.jansi.internal.Kernel32.GetLastError;

class WindowsSupport {

public static String getLastErrorMessage() {
int errorCode = GetLastError();
int bufferSize = 160;
byte[] data = new byte[bufferSize];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, bufferSize, null);
return new String(data, StandardCharsets.UTF_16LE).trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ public static String posixSystemStreamName(SystemStream stream) {

private static boolean isatty(int fd) {
if (Platform.isMac()) {
if (Platform.is64Bit() && Platform.isARM()) {
throw new UnsupportedOperationException("Unsupported platform mac-aarch64");
}
return OsXNativePty.isatty(fd) == 1;
} else if (Platform.isLinux()) {
return LinuxNativePty.isatty(fd) == 1;
Expand All @@ -204,6 +207,9 @@ private static boolean isatty(int fd) {

private static String ttyname(int fd) {
if (Platform.isMac()) {
if (Platform.is64Bit() && Platform.isARM()) {
throw new UnsupportedOperationException("Unsupported platform mac-aarch64");
}
return OsXNativePty.ttyname(fd);
} else if (Platform.isLinux()) {
return LinuxNativePty.ttyname(fd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
import org.jline.utils.OSUtils;

public class JnaTerminalProvider implements TerminalProvider {

public JnaTerminalProvider() {
checkSystemStream(SystemStream.Output);
}

@Override
public String name() {
return TerminalBuilder.PROP_PROVIDER_JNA;
Expand Down Expand Up @@ -106,22 +111,18 @@ public Terminal newTerminal(
@Override
public boolean isSystemStream(SystemStream stream) {
try {
if (OSUtils.IS_WINDOWS) {
return isWindowsSystemStream(stream);
} else {
return isPosixSystemStream(stream);
}
return checkSystemStream(stream);
} catch (Throwable t) {
return false;
}
}

public boolean isWindowsSystemStream(SystemStream stream) {
return JnaWinSysTerminal.isWindowsSystemStream(stream);
}

public boolean isPosixSystemStream(SystemStream stream) {
return JnaNativePty.isPosixSystemStream(stream);
private boolean checkSystemStream(SystemStream stream) {
if (OSUtils.IS_WINDOWS) {
return JnaWinSysTerminal.isWindowsSystemStream(stream);
} else {
return JnaNativePty.isPosixSystemStream(stream);
}
}

@Override
Expand Down
Loading