8350749: Upgrade JLine to 3.29.0

Reviewed-by: liach
This commit is contained in:
Jan Lahoda 2025-03-20 15:17:10 +00:00
parent 91836e181a
commit 9a17a6ff0f
18 changed files with 174 additions and 50 deletions

View File

@ -10,6 +10,7 @@ package jdk.internal.org.jline.reader;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.function.IntConsumer;
@ -766,7 +767,11 @@ public interface LineReader {
void addCommandsInBuffer(Collection<String> commands);
void editAndAddInBuffer(File file) throws Exception;
default void editAndAddInBuffer(File file) throws Exception {
editAndAddInBuffer(file != null ? file.toPath() : null);
}
void editAndAddInBuffer(Path file) throws Exception;
String getLastBinding();

View File

@ -19,6 +19,11 @@ public class UserInterruptException extends RuntimeException {
private final String partialLine;
public UserInterruptException(Throwable cause) {
super(cause);
this.partialLine = null;
}
public UserInterruptException(String partialLine) {
this.partialLine = partialLine;
}

View File

@ -38,6 +38,7 @@ public class DefaultHighlighter implements Highlighter {
int underlineEnd = -1;
int negativeStart = -1;
int negativeEnd = -1;
boolean first = true;
String search = reader.getSearchTerm();
if (search != null && search.length() > 0) {
underlineStart = buffer.indexOf(search);
@ -65,6 +66,7 @@ public class DefaultHighlighter implements Highlighter {
}
AttributedStringBuilder sb = new AttributedStringBuilder();
commandStyle(reader, sb, true);
for (int i = 0; i < buffer.length(); i++) {
if (i == underlineStart) {
sb.style(AttributedStyle::underline);
@ -77,6 +79,10 @@ public class DefaultHighlighter implements Highlighter {
}
char c = buffer.charAt(i);
if (first && Character.isSpaceChar(c)) {
first = false;
commandStyle(reader, sb, false);
}
if (c == '\t' || c == '\n') {
sb.append(c);
} else if (c < 32) {
@ -105,4 +111,6 @@ public class DefaultHighlighter implements Highlighter {
}
return sb.toAttributedString();
}
protected void commandStyle(LineReader reader, AttributedStringBuilder sb, boolean enable) {}
}

View File

@ -10,7 +10,6 @@ package jdk.internal.org.jline.reader.impl;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Flushable;
import java.io.IOError;
@ -1131,16 +1130,16 @@ public class LineReaderImpl implements LineReader, Flushable {
}
@Override
public void editAndAddInBuffer(File file) throws Exception {
public void editAndAddInBuffer(Path file) throws Exception {
if (isSet(Option.BRACKETED_PASTE)) {
terminal.writer().write(BRACKETED_PASTE_OFF);
}
Constructor<?> ctor = Class.forName("org.jline.builtins.Nano").getConstructor(Terminal.class, File.class);
Editor editor = (Editor) ctor.newInstance(terminal, new File(file.getParent()));
Constructor<?> ctor = Class.forName("org.jline.builtins.Nano").getConstructor(Terminal.class, Path.class);
Editor editor = (Editor) ctor.newInstance(terminal, file.getParent());
editor.setRestricted(true);
editor.open(Collections.singletonList(file.getName()));
editor.open(Collections.singletonList(file.getFileName().toString()));
editor.run();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
try (BufferedReader br = Files.newBufferedReader(file)) {
String line;
commandsBuffer.clear();
while ((line = br.readLine()) != null) {
@ -3529,7 +3528,7 @@ public class LineReaderImpl implements LineReader, Flushable {
buf.move(1);
putString(yankBuffer);
buf.move(-yankBuffer.length());
} else if (yankBuffer.length() != 0) {
} else if (!yankBuffer.isEmpty()) {
if (buf.cursor() < buf.length()) {
buf.move(1);
}
@ -3547,7 +3546,7 @@ public class LineReaderImpl implements LineReader, Flushable {
;
putString(yankBuffer);
buf.move(-yankBuffer.length());
} else if (yankBuffer.length() != 0) {
} else if (!yankBuffer.isEmpty()) {
if (buf.cursor() > 0) {
buf.move(-1);
}

View File

@ -9,6 +9,8 @@
package jdk.internal.org.jline.reader.impl.completer;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import jdk.internal.org.jline.reader.Candidate;
import jdk.internal.org.jline.reader.Completer;
@ -24,6 +26,7 @@ import jdk.internal.org.jline.utils.AttributedString;
public class SystemCompleter implements Completer {
private Map<String, List<Completer>> completers = new HashMap<>();
private Map<String, String> aliasCommand = new HashMap<>();
private Map<String, String> descriptions = new HashMap<>();
private StringsCompleter commands;
private boolean compiled = false;
@ -124,6 +127,10 @@ public class SystemCompleter implements Completer {
}
public void compile() {
compile(s -> new Candidate(AttributedString.stripAnsi(s), s, null, null, null, null, true));
}
public void compile(Function<String, Candidate> candidateBuilder) {
if (compiled) {
return;
}
@ -139,7 +146,7 @@ public class SystemCompleter implements Completer {
completers = compiledCompleters;
Set<String> cmds = new HashSet<>(completers.keySet());
cmds.addAll(aliasCommand.keySet());
commands = new StringsCompleter(cmds);
commands = new StringsCompleter(cmds.stream().map(candidateBuilder).collect(Collectors.toList()));
compiled = true;
}

View File

@ -200,7 +200,7 @@ public class DefaultHistory implements History {
public void write(Path file, boolean incremental) throws IOException {
Path path = file != null ? file : getPath();
if (path != null && Files.exists(path)) {
path.toFile().delete();
Files.deleteIfExists(path);
}
internalWrite(path, incremental ? getLastLoaded(path) : 0);
}

View File

@ -209,41 +209,85 @@ public final class TerminalBuilder {
return this;
}
/**
* Forces the usage of the give terminal provider.
*
* @param provider The {@link TerminalProvider}'s name to use when creating the Terminal.
* @return The builder.
*/
public TerminalBuilder provider(String provider) {
this.provider = provider;
return this;
}
/**
* Sets the list of providers to try when creating the terminal.
* If not specified, the system property {@link #PROP_PROVIDERS} will be used if set.
* Else, the value {@link #PROP_PROVIDERS_DEFAULT} will be used.
*
* @param providers The list of {@link TerminalProvider}'s names to check when creating the Terminal.
* @return The builder.
*/
public TerminalBuilder providers(String providers) {
this.providers = providers;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_JNA}/{@code jna} terminal provider.
* If not specified, the system property {@link #PROP_JNA} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder jna(boolean jna) {
this.jna = jna;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_JANSI}/{@code jansi} terminal provider.
* If not specified, the system property {@link #PROP_JANSI} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder jansi(boolean jansi) {
this.jansi = jansi;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_JNI}/{@code jni} terminal provider.
* If not specified, the system property {@link #PROP_JNI} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder jni(boolean jni) {
this.jni = jni;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_EXEC}/{@code exec} terminal provider.
* If not specified, the system property {@link #PROP_EXEC} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder exec(boolean exec) {
this.exec = exec;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_FFM}/{@code ffm} terminal provider.
* If not specified, the system property {@link #PROP_FFM} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder ffm(boolean ffm) {
this.ffm = ffm;
return this;
}
/**
* Enables or disables the {@link #PROP_PROVIDER_DUMB}/{@code dumb} terminal provider.
* If not specified, the system property {@link #PROP_DUMB} will be used if set.
* If not specified, the provider will be checked.
*/
public TerminalBuilder dumb(boolean dumb) {
this.dumb = dumb;
return this;

View File

@ -94,4 +94,13 @@ public abstract class AbstractPosixTerminal extends AbstractTerminal {
public SystemStream getSystemStream() {
return getPty().getSystemStream();
}
@Override
public String toString() {
return getKind() + "[" + "name='"
+ name + '\'' + ", pty='"
+ pty + '\'' + ", type='"
+ type + '\'' + ", size='"
+ getSize() + '\'' + ']';
}
}

View File

@ -287,4 +287,12 @@ public abstract class AbstractTerminal implements TerminalExt {
public ColorPalette getPalette() {
return palette;
}
@Override
public String toString() {
return getKind() + "[" + "name='"
+ name + '\'' + ", type='"
+ type + '\'' + ", size='"
+ getSize() + '\'' + ']';
}
}

View File

@ -10,7 +10,7 @@ package jdk.internal.org.jline.terminal.impl;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ServiceLoader;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.TimeUnit;
@ -24,10 +24,26 @@ import jdk.internal.org.jline.utils.OSUtils;
public class Diag {
public static void main(String[] args) {
diag(System.out);
diag(System.out, Arrays.asList(args).contains("--verbose"));
}
public static void diag(PrintStream out) {
diag(out, true);
}
public static void diag(PrintStream out, boolean verbose) {
new Diag(out, verbose).run();
}
private final PrintStream out;
private final boolean verbose;
public Diag(PrintStream out, boolean verbose) {
this.out = out;
this.verbose = verbose;
}
public void run() {
out.println("System properties");
out.println("=================");
out.println("os.name = " + System.getProperty("os.name"));
@ -56,9 +72,9 @@ public class Diag {
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("ffm");
testProvider(out, provider);
testProvider(provider);
} catch (Throwable t) {
out.println("FFM support not available: " + t);
error("FFM support not available", t);
}
out.println();
@ -66,9 +82,9 @@ public class Diag {
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("jna");
testProvider(out, provider);
testProvider(provider);
} catch (Throwable t) {
out.println("JNA support not available: " + t);
error("JNA support not available", t);
}
out.println();
@ -76,9 +92,9 @@ public class Diag {
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("jansi");
testProvider(out, provider);
testProvider(provider);
} catch (Throwable t) {
out.println("Jansi 2 support not available: " + t);
error("Jansi 2 support not available", t);
}
out.println();
@ -86,9 +102,9 @@ public class Diag {
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("jni");
testProvider(out, provider);
testProvider(provider);
} catch (Throwable t) {
out.println("JNI support not available: " + t);
error("JNI support not available", t);
}
out.println();
@ -97,26 +113,31 @@ public class Diag {
out.println("=================");
try {
TerminalProvider provider = TerminalProvider.load("exec");
testProvider(out, provider);
testProvider(provider);
} catch (Throwable t) {
out.println("Exec support not available: " + t);
error("Exec support not available", t);
}
if (!verbose) {
out.println();
out.println("Run with --verbose argument to print stack traces");
}
}
private static void testProvider(PrintStream out, TerminalProvider provider) {
private void testProvider(TerminalProvider provider) {
try {
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);
} catch (Throwable t) {
error("Unable to check stream", t);
}
try {
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);
} catch (Throwable t) {
error("Unable to check stream names", t);
}
try (Terminal terminal = provider.sysTerminal(
"diag",
@ -132,9 +153,14 @@ public class Diag {
Attributes attr = terminal.enterRawMode();
try {
out.println("Terminal size: " + terminal.getSize());
ForkJoinTask<Integer> t =
new ForkJoinPool(1).submit(() -> terminal.reader().read(1));
int r = t.get(1000, TimeUnit.MILLISECONDS);
ForkJoinPool forkJoinPool = new ForkJoinPool(1);
try {
ForkJoinTask<Integer> t =
forkJoinPool.submit(() -> terminal.reader().read(1));
t.get(1000, TimeUnit.MILLISECONDS);
} finally {
forkJoinPool.shutdown();
}
StringBuilder sb = new StringBuilder();
sb.append("The terminal seems to work: ");
sb.append("terminal ").append(terminal.getClass().getName());
@ -146,22 +172,25 @@ public class Diag {
.getName());
}
out.println(sb);
} catch (Throwable t3) {
out.println("Unable to read from terminal: " + t3);
t3.printStackTrace();
} catch (Throwable t2) {
error("Unable to read from terminal", t2);
} finally {
terminal.setAttributes(attr);
}
} else {
out.println("Not supported by provider");
}
} catch (Throwable t2) {
out.println("Unable to open terminal: " + t2);
t2.printStackTrace();
} catch (Throwable t) {
error("Unable to open terminal", t);
}
}
static <S> S load(Class<S> clazz) {
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
private void error(String message, Throwable cause) {
if (verbose) {
out.println(message);
cause.printStackTrace(out);
} else {
out.println(message + ": " + cause);
}
}
}

View File

@ -278,7 +278,7 @@ public class ExecPty extends AbstractPty implements Pty {
return Integer.parseInt(matcher.group(1));
}
}
throw new IOException("Unable to parse " + name);
return 0;
}
@Override

View File

@ -46,6 +46,9 @@ public class ExecTerminalProvider implements TerminalProvider {
}
public Pty current(SystemStream systemStream) throws IOException {
if (!isSystemStream(systemStream)) {
throw new IOException("Not a system stream: " + systemStream);
}
return ExecPty.current(this, systemStream);
}

View File

@ -19,7 +19,7 @@ final class Kernel32 {
public static final int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
public static final int INVALID_HANDLE_VALUE = -1;
public static final long INVALID_HANDLE_VALUE = -1;
public static final int STD_INPUT_HANDLE = -10;
public static final int STD_OUTPUT_HANDLE = -11;
public static final int STD_ERROR_HANDLE = -12;
@ -235,8 +235,8 @@ final class Kernel32 {
CHAR_INFO lpFill) {
MethodHandle mh$ = requireNonNull(ScrollConsoleScreenBufferW$MH, "ScrollConsoleScreenBuffer");
try {
return (int)
mh$.invokeExact(hConsoleOutput, lpScrollRectangle.seg, lpClipRectangle.seg, dwDestinationOrigin.seg, lpFill.seg);
return (int) mh$.invokeExact(
hConsoleOutput, lpScrollRectangle.seg, lpClipRectangle.seg, dwDestinationOrigin.seg, lpFill.seg);
} catch (Throwable ex$) {
throw new AssertionError("should not reach here", ex$);
}

View File

@ -83,7 +83,7 @@ public class NativeWinSysTerminal extends AbstractWindowsTerminal<java.lang.fore
type = type != null ? type : OSUtils.IS_CONEMU ? TYPE_WINDOWS_CONEMU : TYPE_WINDOWS;
writer = new NativeWinConsoleWriter();
} else {
int m = inMode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0);
int m = outMode.get(java.lang.foreign.ValueLayout.JAVA_INT, 0);
if (enableVtp(console, m)) {
type = type != null ? type : TYPE_WINDOWS_VTP;
writer = new NativeWinConsoleWriter();

View File

@ -219,7 +219,8 @@ public class Display {
cursorPos++;
if (newLength == 0 || newLine.isHidden(0)) {
// go to next line column zero
rawPrint(new AttributedString(" \b"));
rawPrint(' ');
terminal.puts(Capability.key_backspace);
} else {
AttributedString firstChar = newLine.substring(0, 1);
// go to next line column one
@ -319,7 +320,8 @@ public class Display {
} else if (atRight) {
if (this.wrapAtEol) {
if (!fullScreen || (fullScreen && lineIndex < numLines)) {
terminal.writer().write(" \b");
rawPrint(' ');
terminal.puts(Capability.key_backspace);
cursorPos++;
}
} else {

View File

@ -22,8 +22,7 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;
import java.nio.charset.UnmappableCharacterException;
/**
*
/*
* NOTE for JLine: the default InputStreamReader that comes from the JRE
* usually read more bytes than needed from the input stream, which
* is not usable in a character per character model used in the terminal.

View File

@ -48,7 +48,8 @@ public class Status {
this.supported = terminal.getStringCapability(Capability.change_scroll_region) != null
&& terminal.getStringCapability(Capability.save_cursor) != null
&& terminal.getStringCapability(Capability.restore_cursor) != null
&& terminal.getStringCapability(Capability.cursor_address) != null;
&& terminal.getStringCapability(Capability.cursor_address) != null
&& isValid(terminal.getSize());
if (supported) {
display = new MovingCursorDisplay(terminal);
resize();
@ -57,6 +58,10 @@ public class Status {
}
}
private boolean isValid(Size size) {
return size.getRows() > 0 && size.getRows() < 1000 && size.getColumns() > 0 && size.getColumns() < 1000;
}
public void close() {
terminal.puts(Capability.save_cursor);
terminal.puts(Capability.change_scroll_region, 0, display.rows - 1);
@ -147,6 +152,7 @@ public class Status {
if (newScrollRegion < scrollRegion) {
// We need to scroll up to grow the status bar
terminal.puts(Capability.save_cursor);
terminal.puts(Capability.cursor_address, scrollRegion, 0);
for (int i = newScrollRegion; i < scrollRegion; i++) {
terminal.puts(Capability.cursor_down);
}

View File

@ -1,4 +1,4 @@
## JLine v3.26.1
## JLine v3.29.0
### JLine License
<pre>