8297587: Upgrade JLine to 3.22.0
Reviewed-by: vromero
This commit is contained in:
parent
99f5687eb1
commit
4619e8bae8
@ -14,7 +14,7 @@ package jdk.internal.org.jline.reader;
|
||||
* @see Macro
|
||||
* @see Reference
|
||||
* @see Widget
|
||||
* @see org.jline.keymap.KeyMap
|
||||
* @see jdk.internal.org.jline.keymap.KeyMap
|
||||
*
|
||||
* @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
|
||||
*/
|
||||
|
@ -24,6 +24,7 @@ public class Candidate implements Comparable<Candidate> {
|
||||
private final String suffix;
|
||||
private final String key;
|
||||
private final boolean complete;
|
||||
private final int sort;
|
||||
|
||||
/**
|
||||
* Simple constructor with only a single String as an argument.
|
||||
@ -31,7 +32,30 @@ public class Candidate implements Comparable<Candidate> {
|
||||
* @param value the candidate
|
||||
*/
|
||||
public Candidate(String value) {
|
||||
this(value, value, null, null, null, null, true);
|
||||
this(value, value, null, null, null, null, true, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Candidate.
|
||||
*
|
||||
* @param value the value
|
||||
* @param displ the display string
|
||||
* @param group the group
|
||||
* @param descr the description
|
||||
* @param suffix the suffix
|
||||
* @param key the key
|
||||
* @param complete the complete flag
|
||||
* @param sort the sort flag
|
||||
*/
|
||||
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete, int sort) {
|
||||
this.value = Objects.requireNonNull(value);
|
||||
this.displ = Objects.requireNonNull(displ);
|
||||
this.group = group;
|
||||
this.descr = descr;
|
||||
this.suffix = suffix;
|
||||
this.key = key;
|
||||
this.complete = complete;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,13 +70,7 @@ public class Candidate implements Comparable<Candidate> {
|
||||
* @param complete the complete flag
|
||||
*/
|
||||
public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
|
||||
this.value = Objects.requireNonNull(value);
|
||||
this.displ = Objects.requireNonNull(displ);
|
||||
this.group = group;
|
||||
this.descr = descr;
|
||||
this.suffix = suffix;
|
||||
this.key = key;
|
||||
this.complete = complete;
|
||||
this(value, displ, group, descr, suffix, key, complete, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,9 +151,36 @@ public class Candidate implements Comparable<Candidate> {
|
||||
return complete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer used to override default sort logic.
|
||||
* @return the sort int
|
||||
*/
|
||||
public int sort() {
|
||||
return sort;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Candidate o) {
|
||||
return value.compareTo(o.value);
|
||||
// If both candidates have same sort, use default behavior
|
||||
if( sort == o.sort() ) {
|
||||
return value.compareTo(o.value);
|
||||
} else {
|
||||
return Integer.compare(sort, o.sort());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Candidate candidate = (Candidate) o;
|
||||
return Objects.equals(value, candidate.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,7 +10,7 @@ package jdk.internal.org.jline.reader;
|
||||
|
||||
/**
|
||||
* An extension of {@link ParsedLine} that, being aware of the quoting and escaping rules
|
||||
* of the {@link org.jline.reader.Parser} that produced it, knows if and how a completion candidate
|
||||
* of the {@link jdk.internal.org.jline.reader.Parser} that produced it, knows if and how a completion candidate
|
||||
* should be escaped/quoted.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
|
@ -29,7 +29,7 @@ public interface CompletionMatcher {
|
||||
/**
|
||||
*
|
||||
* @param candidates list of candidates
|
||||
* @return a map of candidates that completion matcher matches
|
||||
* @return a list of candidates that completion matcher matches
|
||||
*/
|
||||
List<Candidate> matches(List<Candidate> candidates);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -14,7 +14,28 @@ import jdk.internal.org.jline.utils.AttributedString;
|
||||
|
||||
public interface Highlighter {
|
||||
|
||||
/**
|
||||
* Highlight buffer
|
||||
* @param reader LineReader
|
||||
* @param buffer the buffer to be highlighted
|
||||
* @return highlighted buffer
|
||||
*/
|
||||
AttributedString highlight(LineReader reader, String buffer);
|
||||
public void setErrorPattern(Pattern errorPattern);
|
||||
public void setErrorIndex(int errorIndex);
|
||||
|
||||
/**
|
||||
* Refresh highlight configuration
|
||||
*/
|
||||
default void refresh(LineReader reader) {}
|
||||
|
||||
/**
|
||||
* Set error pattern to be highlighted
|
||||
* @param errorPattern error pattern to be highlighted
|
||||
*/
|
||||
void setErrorPattern(Pattern errorPattern);
|
||||
|
||||
/**
|
||||
* Set error index to be highlighted
|
||||
* @param errorIndex error index to be highlighted
|
||||
*/
|
||||
void setErrorIndex(int errorIndex);
|
||||
}
|
||||
|
@ -61,12 +61,13 @@ public interface History extends Iterable<History.Entry>
|
||||
void append(Path file, boolean incremental) throws IOException;
|
||||
|
||||
/**
|
||||
* Read history from the file. If incremental only the events that are not contained within the internal list are added.
|
||||
* Read history from the file. If checkDuplicates is <code>true</code> only the events that
|
||||
* are not contained within the internal list are added.
|
||||
* @param file History file
|
||||
* @param incremental If true incremental read operation is performed.
|
||||
* @param checkDuplicates If <code>true</code>, duplicate history entries will be discarded
|
||||
* @throws IOException if a problem occurs
|
||||
*/
|
||||
void read(Path file, boolean incremental) throws IOException;
|
||||
void read(Path file, boolean checkDuplicates) throws IOException;
|
||||
|
||||
/**
|
||||
* Purge history.
|
||||
|
@ -352,7 +352,7 @@ public interface LineReader {
|
||||
String AMBIGUOUS_BINDING = "ambiguous-binding";
|
||||
|
||||
/**
|
||||
* Columns separated list of patterns that will not be saved in history.
|
||||
* Colon separated list of patterns that will not be saved in history.
|
||||
*/
|
||||
String HISTORY_IGNORE = "history-ignore";
|
||||
|
||||
@ -467,6 +467,9 @@ public interface LineReader {
|
||||
|
||||
/** Show command options tab completion candidates for zero length word */
|
||||
EMPTY_WORD_OPTIONS(true),
|
||||
|
||||
/** Disable the undo feature */
|
||||
DISABLE_UNDO
|
||||
;
|
||||
|
||||
private final boolean def;
|
||||
@ -699,7 +702,7 @@ public interface LineReader {
|
||||
void runMacro(String macro);
|
||||
|
||||
/**
|
||||
* Read a mouse event when the {@link org.jline.utils.InfoCmp.Capability#key_mouse} sequence
|
||||
* Read a mouse event when the {@link jdk.internal.org.jline.utils.InfoCmp.Capability#key_mouse} sequence
|
||||
* has just been read on the input stream.
|
||||
* Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys
|
||||
* that have been pushed back using {@link #runMacro(String)}.
|
||||
|
@ -118,6 +118,12 @@ public final class LineReaderBuilder {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
String appName = this.appName;
|
||||
if (null == appName) {
|
||||
appName = terminal.getName();
|
||||
}
|
||||
|
||||
LineReaderImpl reader = new LineReaderImpl(terminal, appName, variables);
|
||||
if (history != null) {
|
||||
reader.setHistory(history);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -12,8 +12,8 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public interface Parser {
|
||||
static final String REGEX_VARIABLE = "[a-zA-Z_]{1,}[a-zA-Z0-9_-]*";
|
||||
static final String REGEX_COMMAND = "[:]{0,1}[a-zA-Z]{1,}[a-zA-Z0-9_-]*";
|
||||
String REGEX_VARIABLE = "[a-zA-Z_]+[a-zA-Z0-9_-]*";
|
||||
String REGEX_COMMAND = "[:]?[a-zA-Z]+[a-zA-Z0-9_-]*";
|
||||
|
||||
ParsedLine parse(String line, int cursor, ParseContext context) throws SyntaxError;
|
||||
|
||||
@ -34,7 +34,7 @@ public interface Parser {
|
||||
}
|
||||
|
||||
default String getCommand(final String line) {
|
||||
String out = "";
|
||||
String out;
|
||||
Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)");
|
||||
Matcher matcher = patternCommand.matcher(line);
|
||||
if (matcher.find()) {
|
||||
@ -68,7 +68,7 @@ public interface Parser {
|
||||
|
||||
/** Parsed words will have all characters present in input line
|
||||
* including quotes and escape chars.
|
||||
* May throw EOFError in which case we have incomplete input.
|
||||
* We should tolerate and ignore errors.
|
||||
*/
|
||||
SPLIT_LINE,
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class CompletionMatcherImpl implements CompletionMatcher {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList())
|
||||
return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).distinct().collect(Collectors.toList())
|
||||
: new ArrayList<>();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,27 @@ public class DefaultParser implements Parser {
|
||||
ANGLE // <>
|
||||
}
|
||||
|
||||
public static class BlockCommentDelims {
|
||||
private final String start;
|
||||
private final String end;
|
||||
public BlockCommentDelims(String start, String end) {
|
||||
if (start == null || end == null
|
||||
|| start.isEmpty() || end.isEmpty() || start.equals(end)) {
|
||||
throw new IllegalArgumentException("Bad block comment delimiter!");
|
||||
}
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public String getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public String getEnd() {
|
||||
return end;
|
||||
}
|
||||
}
|
||||
|
||||
private char[] quoteChars = {'\'', '"'};
|
||||
|
||||
private char[] escapeChars = {'\\'};
|
||||
@ -39,6 +60,10 @@ public class DefaultParser implements Parser {
|
||||
|
||||
private char[] closingBrackets = null;
|
||||
|
||||
private String[] lineCommentDelims = null;
|
||||
|
||||
private BlockCommentDelims blockCommentDelims = null;
|
||||
|
||||
private String regexVariable = "[a-zA-Z_]+[a-zA-Z0-9_-]*((\\.|\\['|\\[\"|\\[)[a-zA-Z0-9_-]*(|']|\"]|]))?";
|
||||
private String regexCommand = "[:]?[a-zA-Z]+[a-zA-Z0-9_-]*";
|
||||
private int commandGroup = 4;
|
||||
@ -47,6 +72,16 @@ public class DefaultParser implements Parser {
|
||||
// Chainable setters
|
||||
//
|
||||
|
||||
public DefaultParser lineCommentDelims(final String[] lineCommentDelims) {
|
||||
this.lineCommentDelims = lineCommentDelims;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultParser blockCommentDelims(final BlockCommentDelims blockCommentDelims) {
|
||||
this.blockCommentDelims = blockCommentDelims;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultParser quoteChars(final char[] chars) {
|
||||
this.quoteChars = chars;
|
||||
return this;
|
||||
@ -107,6 +142,22 @@ public class DefaultParser implements Parser {
|
||||
return this.escapeChars;
|
||||
}
|
||||
|
||||
public void setLineCommentDelims(String[] lineCommentDelims) {
|
||||
this.lineCommentDelims = lineCommentDelims;
|
||||
}
|
||||
|
||||
public String[] getLineCommentDelims() {
|
||||
return this.lineCommentDelims;
|
||||
}
|
||||
|
||||
public void setBlockCommentDelims(BlockCommentDelims blockCommentDelims) {
|
||||
this.blockCommentDelims = blockCommentDelims;
|
||||
}
|
||||
|
||||
public BlockCommentDelims getBlockCommentDelims() {
|
||||
return blockCommentDelims;
|
||||
}
|
||||
|
||||
public void setEofOnUnclosedQuote(boolean eofOnUnclosedQuote) {
|
||||
this.eofOnUnclosedQuote = eofOnUnclosedQuote;
|
||||
}
|
||||
@ -225,6 +276,11 @@ public class DefaultParser implements Parser {
|
||||
int rawWordStart = 0;
|
||||
BracketChecker bracketChecker = new BracketChecker(cursor);
|
||||
boolean quotedWord = false;
|
||||
boolean lineCommented = false;
|
||||
boolean blockCommented = false;
|
||||
boolean blockCommentInRightOrder = true;
|
||||
final String blockCommentEnd = blockCommentDelims == null ? null : blockCommentDelims.end;
|
||||
final String blockCommentStart = blockCommentDelims == null ? null : blockCommentDelims.start;
|
||||
|
||||
for (int i = 0; (line != null) && (i < line.length()); i++) {
|
||||
// once we reach the cursor, set the
|
||||
@ -237,7 +293,7 @@ public class DefaultParser implements Parser {
|
||||
rawWordCursor = i - rawWordStart;
|
||||
}
|
||||
|
||||
if (quoteStart < 0 && isQuoteChar(line, i)) {
|
||||
if (quoteStart < 0 && isQuoteChar(line, i) && !lineCommented && !blockCommented) {
|
||||
// Start a quote block
|
||||
quoteStart = i;
|
||||
if (current.length()==0) {
|
||||
@ -258,17 +314,40 @@ public class DefaultParser implements Parser {
|
||||
quoteStart = -1;
|
||||
quotedWord = false;
|
||||
} else if (quoteStart < 0 && isDelimiter(line, i)) {
|
||||
// Delimiter
|
||||
if (current.length() > 0) {
|
||||
words.add(current.toString());
|
||||
current.setLength(0); // reset the arg
|
||||
if (rawWordCursor >= 0 && rawWordLength < 0) {
|
||||
rawWordLength = i - rawWordStart;
|
||||
if (lineCommented) {
|
||||
if (isCommentDelim(line, i, System.lineSeparator())) {
|
||||
lineCommented = false;
|
||||
}
|
||||
} else if (blockCommented) {
|
||||
if (isCommentDelim(line, i, blockCommentEnd)) {
|
||||
blockCommented = false;
|
||||
}
|
||||
} else {
|
||||
// Delimiter
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
rawWordStart = i + 1;
|
||||
}
|
||||
rawWordStart = i + 1;
|
||||
} else {
|
||||
if (!isEscapeChar(line, i)) {
|
||||
if (quoteStart < 0 && !blockCommented && (lineCommented || isLineCommentStarted(line, i))) {
|
||||
lineCommented = true;
|
||||
} else if (quoteStart < 0 && !lineCommented
|
||||
&& (blockCommented || isCommentDelim(line, i, blockCommentStart))) {
|
||||
if (blockCommented) {
|
||||
if (blockCommentEnd != null && isCommentDelim(line, i, blockCommentEnd)) {
|
||||
blockCommented = false;
|
||||
i += blockCommentEnd.length() - 1;
|
||||
}
|
||||
} else {
|
||||
blockCommented = true;
|
||||
rawWordLength = handleDelimiterAndGetRawWordLength(current, words, rawWordStart, rawWordCursor, rawWordLength, i);
|
||||
i += blockCommentStart == null ? 0 : blockCommentStart.length() - 1;
|
||||
rawWordStart = i + 1;
|
||||
}
|
||||
} else if (quoteStart < 0 && !lineCommented
|
||||
&& isCommentDelim(line, i, blockCommentEnd)) {
|
||||
current.append(line.charAt(i));
|
||||
blockCommentInRightOrder = false;
|
||||
} else if (!isEscapeChar(line, i)) {
|
||||
current.append(line.charAt(i));
|
||||
if (quoteStart < 0) {
|
||||
bracketChecker.check(line, i);
|
||||
@ -301,6 +380,14 @@ public class DefaultParser implements Parser {
|
||||
throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
|
||||
? "quote" : "dquote");
|
||||
}
|
||||
if (blockCommented) {
|
||||
throw new EOFError(-1, -1, "Missing closing block comment delimiter",
|
||||
"add: " + blockCommentEnd);
|
||||
}
|
||||
if (!blockCommentInRightOrder) {
|
||||
throw new EOFError(-1, -1, "Missing opening block comment delimiter",
|
||||
"missing: " + blockCommentStart);
|
||||
}
|
||||
if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) {
|
||||
String message = null;
|
||||
String missing = null;
|
||||
@ -333,6 +420,17 @@ public class DefaultParser implements Parser {
|
||||
return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
|
||||
}
|
||||
|
||||
private int handleDelimiterAndGetRawWordLength(StringBuilder current, List<String> words, int rawWordStart, int rawWordCursor, int rawWordLength, int pos) {
|
||||
if (current.length() > 0) {
|
||||
words.add(current.toString());
|
||||
current.setLength(0); // reset the arg
|
||||
if (rawWordCursor >= 0 && rawWordLength < 0) {
|
||||
return pos - rawWordStart;
|
||||
}
|
||||
}
|
||||
return rawWordLength;
|
||||
}
|
||||
|
||||
public boolean isQuoted(final CharSequence buffer, final int pos) {
|
||||
return false;
|
||||
}
|
||||
@ -351,6 +449,36 @@ public class DefaultParser implements Parser {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCommentDelim(final CharSequence buffer, final int pos, final String pattern) {
|
||||
if (pos < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pattern != null) {
|
||||
final int length = pattern.length();
|
||||
if (length <= buffer.length() - pos) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (pattern.charAt(i) != buffer.charAt(pos + i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isLineCommentStarted(final CharSequence buffer, final int pos) {
|
||||
if (lineCommentDelims != null) {
|
||||
for (String comment: lineCommentDelims) {
|
||||
if (isCommentDelim(buffer, pos, comment)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEscapeChar(char ch) {
|
||||
if (escapeChars != null) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2022, the original author or authors.
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -281,7 +281,7 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
int candidateStartPosition = 0;
|
||||
|
||||
public LineReaderImpl(Terminal terminal) throws IOException {
|
||||
this(terminal, null, null);
|
||||
this(terminal, terminal.getName(), null);
|
||||
}
|
||||
|
||||
public LineReaderImpl(Terminal terminal, String appName) throws IOException {
|
||||
@ -633,7 +633,8 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
|
||||
callWidget(CALLBACK_INIT);
|
||||
|
||||
undo.newState(buf.copy());
|
||||
if (!isSet(Option.DISABLE_UNDO))
|
||||
undo.newState(buf.copy());
|
||||
|
||||
// Draw initial prompt
|
||||
redrawLine();
|
||||
@ -679,7 +680,7 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
if (!w.apply()) {
|
||||
beep();
|
||||
}
|
||||
if (!isUndo && copy != null && buf.length() <= getInt(FEATURES_MAX_BUFFER_SIZE, DEFAULT_FEATURES_MAX_BUFFER_SIZE)
|
||||
if (!isSet(Option.DISABLE_UNDO) && !isUndo && copy != null && buf.length() <= getInt(FEATURES_MAX_BUFFER_SIZE, DEFAULT_FEATURES_MAX_BUFFER_SIZE)
|
||||
&& !copy.toString().equals(buf.toString())) {
|
||||
undo.newState(buf.copy());
|
||||
}
|
||||
@ -739,8 +740,8 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
startedReading.set(false);
|
||||
}
|
||||
startedReading.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1082,18 +1083,18 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
if (isSet(Option.BRACKETED_PASTE)) {
|
||||
terminal.writer().write(BRACKETED_PASTE_OFF);
|
||||
}
|
||||
Constructor<?> ctor = Class.forName("org.jline.builtins.Nano").getConstructor(Terminal.class, File.class);
|
||||
Constructor<?> ctor = Class.forName("jdk.internal.org.jline.builtins.Nano").getConstructor(Terminal.class, File.class);
|
||||
Editor editor = (Editor) ctor.newInstance(terminal, new File(file.getParent()));
|
||||
editor.setRestricted(true);
|
||||
editor.open(Collections.singletonList(file.getName()));
|
||||
editor.run();
|
||||
BufferedReader br = new BufferedReader(new FileReader(file));
|
||||
String line;
|
||||
commandsBuffer.clear();
|
||||
while ((line = br.readLine()) != null) {
|
||||
commandsBuffer.add(line);
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
commandsBuffer.clear();
|
||||
while ((line = br.readLine()) != null) {
|
||||
commandsBuffer.add(line);
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
//
|
||||
@ -3595,9 +3596,9 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
File file = null;
|
||||
try {
|
||||
file = File.createTempFile("jline-execute-", null);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(buf.toString());
|
||||
writer.close();
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
editAndAddInBuffer(file);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(terminal.writer());
|
||||
@ -3796,6 +3797,9 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
|
||||
Status status = Status.getStatus(terminal, false);
|
||||
if (status != null) {
|
||||
if (terminal.getType().startsWith(AbstractWindowsTerminal.TYPE_WINDOWS)) {
|
||||
status.resize();
|
||||
}
|
||||
status.redraw();
|
||||
}
|
||||
|
||||
@ -3947,7 +3951,8 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c: buffer.replace("\\", "\\\\").toCharArray()) {
|
||||
if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '*'
|
||||
|| c == '$' || c == '.' || c == '?' || c == '+') {
|
||||
|| c == '$' || c == '.' || c == '?' || c == '+' || c == '|' || c == '<' || c == '>' || c == '!'
|
||||
|| c == '-') {
|
||||
sb.append('\\');
|
||||
}
|
||||
sb.append(c);
|
||||
@ -4520,7 +4525,7 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
}
|
||||
}
|
||||
|
||||
private CompletingParsedLine wrap(ParsedLine line) {
|
||||
protected static CompletingParsedLine wrap(ParsedLine line) {
|
||||
if (line instanceof CompletingParsedLine) {
|
||||
return (CompletingParsedLine) line;
|
||||
} else {
|
||||
@ -4625,6 +4630,11 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
return size.getRows() - (status != null ? status.size() : 0);
|
||||
}
|
||||
|
||||
private int visibleDisplayRows() {
|
||||
Status status = Status.getStatus(terminal, false);
|
||||
return terminal.getSize().getRows() - (status != null ? status.size() : 0);
|
||||
}
|
||||
|
||||
private int promptLines() {
|
||||
AttributedString text = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>());
|
||||
return text.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size();
|
||||
@ -5070,18 +5080,19 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
|
||||
protected PostResult computePost(List<Candidate> possible, Candidate selection, List<Candidate> ordered, String completed, Function<String, Integer> wcwidth, int width, boolean autoGroup, boolean groupName, boolean rowsFirst) {
|
||||
List<Object> strings = new ArrayList<>();
|
||||
boolean customOrder = possible.stream().anyMatch(c -> c.sort() != 0);
|
||||
if (groupName) {
|
||||
Comparator<String> groupComparator = getGroupComparator();
|
||||
Map<String, Map<String, Candidate>> sorted;
|
||||
Map<String, Map<Object, Candidate>> sorted;
|
||||
sorted = groupComparator != null
|
||||
? new TreeMap<>(groupComparator)
|
||||
: new LinkedHashMap<>();
|
||||
for (Candidate cand : possible) {
|
||||
String group = cand.group();
|
||||
sorted.computeIfAbsent(group != null ? group : "", s -> new LinkedHashMap<>())
|
||||
.put(cand.value(), cand);
|
||||
.put((customOrder ? cand.sort() : cand.value()), cand);
|
||||
}
|
||||
for (Map.Entry<String, Map<String, Candidate>> entry : sorted.entrySet()) {
|
||||
for (Map.Entry<String, Map<Object, Candidate>> entry : sorted.entrySet()) {
|
||||
String group = entry.getKey();
|
||||
if (group.isEmpty() && sorted.size() > 1) {
|
||||
group = getOthersGroupName();
|
||||
@ -5096,13 +5107,13 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
}
|
||||
} else {
|
||||
Set<String> groups = new LinkedHashSet<>();
|
||||
TreeMap<String, Candidate> sorted = new TreeMap<>();
|
||||
TreeMap<Object, Candidate> sorted = new TreeMap<>();
|
||||
for (Candidate cand : possible) {
|
||||
String group = cand.group();
|
||||
if (group != null) {
|
||||
groups.add(group);
|
||||
}
|
||||
sorted.put(cand.value(), cand);
|
||||
sorted.put((customOrder ? cand.sort() : cand.value()), cand);
|
||||
}
|
||||
if (autoGroup) {
|
||||
strings.addAll(groups);
|
||||
@ -5129,7 +5140,7 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
this.startPos = startPos;
|
||||
endLine = line.substring(line.lastIndexOf('\n') + 1);
|
||||
boolean first = true;
|
||||
while (endLine.length() + (first ? startPos : 0) > width) {
|
||||
while (endLine.length() + (first ? startPos : 0) > width && width > 0) {
|
||||
if (first) {
|
||||
endLine = endLine.substring(width - startPos);
|
||||
} else {
|
||||
@ -5207,7 +5218,7 @@ public class LineReaderImpl implements LineReader, Flushable
|
||||
AttributedStringBuilder sb = new AttributedStringBuilder();
|
||||
if (listSize > 0) {
|
||||
if (isSet(Option.AUTO_MENU_LIST)
|
||||
&& listSize < Math.min(getInt(MENU_LIST_MAX, DEFAULT_MENU_LIST_MAX), displayRows() - promptLines())) {
|
||||
&& listSize < Math.min(getInt(MENU_LIST_MAX, DEFAULT_MENU_LIST_MAX), visibleDisplayRows() - promptLines())) {
|
||||
maxWidth = Math.max(maxWidth, MENU_LIST_WIDTH);
|
||||
sb.tabs(Math.max(Math.min(candidateStartPosition, width - maxWidth - 1), 1));
|
||||
width = maxWidth + 2;
|
||||
|
@ -41,7 +41,7 @@ import jdk.internal.org.jline.utils.AttributedStyle;
|
||||
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
|
||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||
* @since 2.3
|
||||
* @deprecated use <code>org.jline.builtins.Completers$FileNameCompleter</code> instead
|
||||
* @deprecated use <code>jdk.internal.org.jline.builtins.Completers$FileNameCompleter</code> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileNameCompleter implements Completer
|
||||
|
@ -67,7 +67,7 @@ public class SystemCompleter implements Completer {
|
||||
if (cmd != null) {
|
||||
if (completers.containsKey(cmd)) {
|
||||
out = cmd;
|
||||
} else if (aliasCommand.containsKey(cmd)) {
|
||||
} else {
|
||||
out = aliasCommand.get(cmd);
|
||||
}
|
||||
}
|
||||
|
@ -97,14 +97,14 @@ public class DefaultHistory implements History {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(Path file, boolean incremental) throws IOException {
|
||||
public void read(Path file, boolean checkDuplicates) throws IOException {
|
||||
Path path = file != null ? file : getPath();
|
||||
if (path != null) {
|
||||
try {
|
||||
if (Files.exists(path)) {
|
||||
Log.trace("Reading history from: ", path);
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
reader.lines().forEach(line -> addHistoryLine(path, line, incremental));
|
||||
reader.lines().forEach(line -> addHistoryLine(path, line, checkDuplicates));
|
||||
setHistoryFileData(path, new HistoryFileData(items.size(), offset + items.size()));
|
||||
maybeResize();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
* Copyright (c) 2002-2021, the original author or authors.
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -16,22 +16,24 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractPosixTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.DumbTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.ExecPty;
|
||||
import jdk.internal.org.jline.terminal.impl.ExternalTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixPtyTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.JansiSupport;
|
||||
import jdk.internal.org.jline.terminal.spi.JnaSupport;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.Log;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
@ -52,6 +54,11 @@ public final class TerminalBuilder {
|
||||
public static final String PROP_EXEC = "org.jline.terminal.exec";
|
||||
public static final String PROP_DUMB = "org.jline.terminal.dumb";
|
||||
public static final String PROP_DUMB_COLOR = "org.jline.terminal.dumb.color";
|
||||
public static final String PROP_OUTPUT = "org.jline.terminal.output";
|
||||
public static final String PROP_OUTPUT_OUT = "out";
|
||||
public static final String PROP_OUTPUT_ERR = "err";
|
||||
public static final String PROP_OUTPUT_OUT_ERR = "out-err";
|
||||
public static final String PROP_OUTPUT_ERR_OUT = "err-out";
|
||||
|
||||
//
|
||||
// Other system properties controlling various jline parts
|
||||
@ -61,6 +68,16 @@ public final class TerminalBuilder {
|
||||
public static final String PROP_COLOR_DISTANCE = "org.jline.utils.colorDistance";
|
||||
public static final String PROP_DISABLE_ALTERNATE_CHARSET = "org.jline.utils.disableAlternateCharset";
|
||||
|
||||
//
|
||||
// Terminal output control
|
||||
//
|
||||
public enum SystemOutput {
|
||||
SysOut,
|
||||
SysErr,
|
||||
SysOutOrSysErr,
|
||||
SysErrOrSysOut
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default system terminal.
|
||||
* Terminals should be closed properly using the {@link Terminal#close()}
|
||||
@ -97,6 +114,7 @@ public final class TerminalBuilder {
|
||||
private Charset encoding;
|
||||
private int codepage;
|
||||
private Boolean system;
|
||||
private SystemOutput systemOutput;
|
||||
private Boolean jna;
|
||||
private Boolean jansi;
|
||||
private Boolean exec;
|
||||
@ -128,6 +146,20 @@ public final class TerminalBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates which standard stream should be used when displaying to the terminal.
|
||||
* The default is to use the system output stream.
|
||||
* Building a system terminal will fail if one of the stream specified is not linked
|
||||
* to the controlling terminal.
|
||||
*
|
||||
* @param systemOutput The mode to choose the output stream.
|
||||
* @return The builder.
|
||||
*/
|
||||
public TerminalBuilder systemOutput(SystemOutput systemOutput) {
|
||||
this.systemOutput = systemOutput;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerminalBuilder jna(boolean jna) {
|
||||
this.jna = jna;
|
||||
return this;
|
||||
@ -298,11 +330,18 @@ public final class TerminalBuilder {
|
||||
encoding = Charset.forName(charsetName);
|
||||
}
|
||||
}
|
||||
int codepage = this.codepage;
|
||||
if (codepage <= 0) {
|
||||
String str = System.getProperty(PROP_CODEPAGE);
|
||||
if (str != null) {
|
||||
codepage = Integer.parseInt(str);
|
||||
if (encoding == null) {
|
||||
int codepage = this.codepage;
|
||||
if (codepage <= 0) {
|
||||
String str = System.getProperty(PROP_CODEPAGE);
|
||||
if (str != null) {
|
||||
codepage = Integer.parseInt(str);
|
||||
}
|
||||
}
|
||||
if (codepage >= 0) {
|
||||
encoding = getCodepageCharset(codepage);
|
||||
} else {
|
||||
encoding = StandardCharsets.UTF_8;
|
||||
}
|
||||
}
|
||||
String type = this.type;
|
||||
@ -328,102 +367,112 @@ public final class TerminalBuilder {
|
||||
if (dumb == null) {
|
||||
dumb = getBoolean(PROP_DUMB, null);
|
||||
}
|
||||
IllegalStateException exception = new IllegalStateException("Unable to create a terminal");
|
||||
List<TerminalProvider> providers = new ArrayList<>();
|
||||
if (jna) {
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jna");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load JNA support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (jansi) {
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jansi");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load JANSI support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (exec)
|
||||
{
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("exec");
|
||||
providers.add(provider);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Unable to load EXEC support: ", t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
|
||||
Terminal terminal = null;
|
||||
if ((system != null && system) || (system == null && in == null && out == null)) {
|
||||
if (system != null && ((in != null && !in.equals(System.in)) || (out != null && !out.equals(System.out)))) {
|
||||
if (system != null && ((in != null && !in.equals(System.in)) ||
|
||||
(out != null && !out.equals(System.out) && !out.equals(System.err)))) {
|
||||
throw new IllegalArgumentException("Cannot create a system terminal using non System streams");
|
||||
}
|
||||
Terminal terminal = null;
|
||||
IllegalStateException exception = new IllegalStateException("Unable to create a system terminal");
|
||||
TerminalBuilderSupport tbs = new TerminalBuilderSupport(jna, jansi);
|
||||
if (tbs.isConsoleInput() && tbs.isConsoleOutput()) {
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
if (out != null) {
|
||||
if (out.equals(System.out)) {
|
||||
systemOutput = SystemOutput.SysOut;
|
||||
} else if (out.equals(System.err)) {
|
||||
systemOutput = SystemOutput.SysErr;
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
String str = System.getProperty(PROP_OUTPUT);
|
||||
if (str != null) {
|
||||
switch (str.trim().toLowerCase(Locale.ROOT)) {
|
||||
case PROP_OUTPUT_OUT: systemOutput = SystemOutput.SysOut; break;
|
||||
case PROP_OUTPUT_ERR: systemOutput = SystemOutput.SysErr; break;
|
||||
case PROP_OUTPUT_OUT_ERR: systemOutput = SystemOutput.SysOutOrSysErr; break;
|
||||
case PROP_OUTPUT_ERR_OUT: systemOutput = SystemOutput.SysErrOrSysOut; break;
|
||||
default:
|
||||
Log.debug("Unsupported value for " + PROP_OUTPUT + ": " + str + ". Supported values are: "
|
||||
+ String.join(", ", PROP_OUTPUT_OUT, PROP_OUTPUT_ERR, PROP_OUTPUT_OUT_ERR,PROP_OUTPUT_ERR_OUT)
|
||||
+ ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (systemOutput == null) {
|
||||
systemOutput = SystemOutput.SysOutOrSysErr;
|
||||
}
|
||||
Map<TerminalProvider.Stream, Boolean> system = Stream.of(TerminalProvider.Stream.values())
|
||||
.collect(Collectors.toMap(stream -> stream, stream -> providers.stream().anyMatch(p -> p.isSystemStream(stream))));
|
||||
TerminalProvider.Stream console = select(system, systemOutput);
|
||||
|
||||
if (system.get(TerminalProvider.Stream.Input) && console != null) {
|
||||
if (attributes != null || size != null) {
|
||||
Log.warn("Attributes and size fields are ignored when creating a system terminal");
|
||||
}
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
if (!OSUtils.IS_CYGWIN && !OSUtils.IS_MSYSTEM) {
|
||||
boolean ansiPassThrough = OSUtils.IS_CONEMU;
|
||||
if (tbs.hasJnaSupport()) {
|
||||
try {
|
||||
terminal = tbs.getJnaSupport().winSysTerminal(name, type, ansiPassThrough, encoding, codepage
|
||||
, nativeSignals, signalHandler, paused, inputStreamWrapper);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (terminal == null && tbs.hasJansiSupport()) {
|
||||
try {
|
||||
terminal = tbs.getJansiSupport().winSysTerminal(name, type, ansiPassThrough, encoding, codepage
|
||||
, nativeSignals, signalHandler, paused);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
} else if (exec) {
|
||||
//
|
||||
// Cygwin support
|
||||
//
|
||||
boolean ansiPassThrough = OSUtils.IS_CONEMU;
|
||||
// Cygwin defaults to XTERM, but actually supports 256 colors,
|
||||
// so if the value comes from the environment, change it to xterm-256color
|
||||
if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) && "xterm".equals(type)
|
||||
&& this.type == null && System.getProperty(PROP_TYPE) == null) {
|
||||
type = "xterm-256color";
|
||||
}
|
||||
for ( TerminalProvider provider : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
// Cygwin defaults to XTERM, but actually supports 256 colors,
|
||||
// so if the value comes from the environment, change it to xterm-256color
|
||||
if ("xterm".equals(type) && this.type == null && System.getProperty(PROP_TYPE) == null) {
|
||||
type = "xterm-256color";
|
||||
}
|
||||
Pty pty = tbs.getExecPty();
|
||||
terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
|
||||
} catch (IOException e) {
|
||||
// Ignore if not a tty
|
||||
Log.debug("Error creating EXEC based terminal: ", e.getMessage(), e);
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
if (terminal == null && !jna && !jansi && (dumb == null || !dumb)) {
|
||||
throw new IllegalStateException("Unable to create a system terminal. On windows, either "
|
||||
+ "JNA or JANSI library is required. Make sure to add one of those in the classpath.");
|
||||
}
|
||||
} else {
|
||||
if (tbs.hasJnaSupport()) {
|
||||
try {
|
||||
Pty pty = tbs.getJnaSupport().current();
|
||||
terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
|
||||
terminal = provider.sysTerminal(name, type, ansiPassThrough, encoding,
|
||||
nativeSignals, signalHandler, paused, console, inputStreamWrapper);
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (terminal == null && tbs.hasJansiSupport()) {
|
||||
try {
|
||||
Pty pty = tbs.getJansiSupport().current();
|
||||
terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
if (terminal == null && exec) {
|
||||
try {
|
||||
Pty pty = tbs.getExecPty();
|
||||
terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
|
||||
} catch (Throwable t) {
|
||||
// Ignore if not a tty
|
||||
Log.debug("Error creating EXEC based terminal: ", t.getMessage(), t);
|
||||
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terminal instanceof AbstractTerminal) {
|
||||
AbstractTerminal t = (AbstractTerminal) terminal;
|
||||
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
|
||||
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
|
||||
} else {
|
||||
exception.addSuppressed(new IllegalStateException("A system terminal is already running. " +
|
||||
"Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " +
|
||||
"or that previously created system Terminals have been correctly closed."));
|
||||
terminal.close();
|
||||
terminal = null;
|
||||
}
|
||||
if (terminal == null && OSUtils.IS_WINDOWS && !jna && !jansi && (dumb == null || !dumb)) {
|
||||
throw new IllegalStateException("Unable to create a system terminal. On windows, either "
|
||||
+ "JNA or JANSI library is required. Make sure to add one of those in the classpath.");
|
||||
}
|
||||
}
|
||||
if (terminal instanceof AbstractTerminal) {
|
||||
AbstractTerminal t = (AbstractTerminal) terminal;
|
||||
if (SYSTEM_TERMINAL.compareAndSet(null, t)) {
|
||||
t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null));
|
||||
} else {
|
||||
exception.addSuppressed(new IllegalStateException("A system terminal is already running. " +
|
||||
"Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " +
|
||||
"or that previously created system Terminals have been correctly closed."));
|
||||
terminal.close();
|
||||
terminal = null;
|
||||
}
|
||||
}
|
||||
if (terminal == null && (dumb == null || dumb)) {
|
||||
@ -433,7 +482,8 @@ public final class TerminalBuilder {
|
||||
color = getBoolean(PROP_DUMB_COLOR, false);
|
||||
// detect emacs using the env variable
|
||||
if (!color) {
|
||||
color = System.getenv("INSIDE_EMACS") != null;
|
||||
String emacs = System.getenv("INSIDE_EMACS");
|
||||
color = emacs != null && emacs.contains("comint");
|
||||
}
|
||||
// detect Intellij Idea
|
||||
if (!color) {
|
||||
@ -441,12 +491,13 @@ public final class TerminalBuilder {
|
||||
color = command != null && command.contains("idea");
|
||||
}
|
||||
if (!color) {
|
||||
color = tbs.isConsoleOutput() && System.getenv("TERM") != null;
|
||||
color = system.get(TerminalProvider.Stream.Output) && System.getenv("TERM") != null;
|
||||
}
|
||||
if (!color && dumb == null) {
|
||||
if (Log.isDebugEnabled()) {
|
||||
Log.warn("input is tty: {}", tbs.isConsoleInput());
|
||||
Log.warn("output is tty: {}", tbs.isConsoleOutput());
|
||||
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("Creating a dumb terminal", exception);
|
||||
} else {
|
||||
Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
|
||||
@ -454,33 +505,49 @@ public final class TerminalBuilder {
|
||||
}
|
||||
}
|
||||
terminal = new DumbTerminal(name, color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB,
|
||||
inputStreamWrapper.apply(new FileInputStream(FileDescriptor.in)),
|
||||
new FileOutputStream(FileDescriptor.out),
|
||||
new FileInputStream(FileDescriptor.in),
|
||||
new FileOutputStream(console == TerminalProvider.Stream.Output ? FileDescriptor.out : FileDescriptor.err),
|
||||
encoding, signalHandler);
|
||||
}
|
||||
if (terminal == null) {
|
||||
throw exception;
|
||||
}
|
||||
return terminal;
|
||||
} else {
|
||||
if (jna) {
|
||||
try {
|
||||
Pty pty = load(JnaSupport.class).open(attributes, size);
|
||||
return new PosixPtyTerminal(name, type, pty, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
|
||||
for ( TerminalProvider provider : providers) {
|
||||
if (terminal == null) {
|
||||
try {
|
||||
terminal = provider.newTerminal(name, type, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused, attributes, size);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating " + provider.name() + " based terminal: ", t.getMessage(), t);
|
||||
exception.addSuppressed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jansi) {
|
||||
try {
|
||||
Pty pty = load(JansiSupport.class).open(attributes, size);
|
||||
return new PosixPtyTerminal(name, type, pty, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused);
|
||||
} catch (Throwable t) {
|
||||
Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
return new ExternalTerminal(name, type, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused, attributes, size);
|
||||
}
|
||||
if (terminal == null) {
|
||||
throw exception;
|
||||
}
|
||||
return terminal;
|
||||
}
|
||||
|
||||
private TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, SystemOutput systemOutput) {
|
||||
switch (systemOutput) {
|
||||
case SysOut:
|
||||
return select(system, TerminalProvider.Stream.Output);
|
||||
case SysErr:
|
||||
return select(system, TerminalProvider.Stream.Error);
|
||||
case SysOutOrSysErr:
|
||||
return select(system, TerminalProvider.Stream.Output, TerminalProvider.Stream.Error);
|
||||
case SysErrOrSysOut:
|
||||
return select(system, TerminalProvider.Stream.Error, TerminalProvider.Stream.Output);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TerminalProvider.Stream select(Map<TerminalProvider.Stream, Boolean> system, TerminalProvider.Stream... streams) {
|
||||
for (TerminalProvider.Stream s : streams) {
|
||||
if (system.get(s)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getParentProcessCommand() {
|
||||
@ -512,6 +579,24 @@ public final class TerminalBuilder {
|
||||
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
|
||||
}
|
||||
|
||||
private static final int UTF8_CODE_PAGE = 65001;
|
||||
|
||||
private static Charset getCodepageCharset(int codepage) {
|
||||
//http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
|
||||
if (codepage == UTF8_CODE_PAGE) {
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
String charsetMS = "ms" + codepage;
|
||||
if (Charset.isSupported(charsetMS)) {
|
||||
return Charset.forName(charsetMS);
|
||||
}
|
||||
String charsetCP = "cp" + codepage;
|
||||
if (Charset.isSupported(charsetCP)) {
|
||||
return Charset.forName(charsetCP);
|
||||
}
|
||||
return Charset.defaultCharset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows an application to override the result of {@link #build()}. The
|
||||
* intended use case is to allow a container or server application to control
|
||||
@ -521,7 +606,7 @@ public final class TerminalBuilder {
|
||||
* build tool uses a <code>LineReader</code> to implement an interactive shell.
|
||||
* One of its supported commands is <code>console</code> which invokes
|
||||
* the scala REPL. The scala REPL also uses a <code>LineReader</code> and it
|
||||
* is necessary to override the {@link Terminal} used by the REPL to
|
||||
* is necessary to override the {@link Terminal} used by the the REPL to
|
||||
* share the same {@link Terminal} instance used by sbt.
|
||||
*
|
||||
* <p>
|
||||
@ -545,79 +630,4 @@ public final class TerminalBuilder {
|
||||
TERMINAL_OVERRIDE.set(terminal);
|
||||
}
|
||||
|
||||
private static class TerminalBuilderSupport {
|
||||
private JansiSupport jansiSupport = null;
|
||||
private JnaSupport jnaSupport = null;
|
||||
private Pty pty = null;
|
||||
private boolean consoleOutput;
|
||||
|
||||
TerminalBuilderSupport(boolean jna, boolean jansi) {
|
||||
if (jna) {
|
||||
try {
|
||||
jnaSupport = load(JnaSupport.class);
|
||||
consoleOutput = jnaSupport.isConsoleOutput();
|
||||
} catch (Throwable e) {
|
||||
jnaSupport = null;
|
||||
Log.debug("jnaSupport.isConsoleOutput(): ", e);
|
||||
}
|
||||
}
|
||||
if (jansi) {
|
||||
try {
|
||||
jansiSupport = load(JansiSupport.class);
|
||||
consoleOutput = jansiSupport.isConsoleOutput();
|
||||
} catch (Throwable e) {
|
||||
jansiSupport = null;
|
||||
Log.debug("jansiSupport.isConsoleOutput(): ", e);
|
||||
}
|
||||
}
|
||||
if (jnaSupport == null && jansiSupport == null) {
|
||||
try {
|
||||
pty = ExecPty.current();
|
||||
consoleOutput = true;
|
||||
} catch (Exception e) {
|
||||
Log.debug("ExecPty.current(): ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConsoleOutput() {
|
||||
return consoleOutput;
|
||||
}
|
||||
|
||||
public boolean isConsoleInput() {
|
||||
if (pty != null) {
|
||||
return true;
|
||||
} else if (hasJnaSupport()) {
|
||||
return jnaSupport.isConsoleInput();
|
||||
} else if (hasJansiSupport()) {
|
||||
return jansiSupport.isConsoleInput();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasJnaSupport() {
|
||||
return jnaSupport != null;
|
||||
}
|
||||
|
||||
public boolean hasJansiSupport() {
|
||||
return jansiSupport != null;
|
||||
}
|
||||
|
||||
public JnaSupport getJnaSupport() {
|
||||
return jnaSupport;
|
||||
}
|
||||
|
||||
public JansiSupport getJansiSupport() {
|
||||
return jansiSupport;
|
||||
}
|
||||
|
||||
public Pty getExecPty() throws IOException {
|
||||
if (pty == null) {
|
||||
pty = ExecPty.current();
|
||||
}
|
||||
return pty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -86,11 +86,6 @@ public abstract class AbstractPty implements Pty {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBuffered(byte[] b) throws IOException {
|
||||
return in.read(b);
|
||||
}
|
||||
|
||||
private void setNonBlocking() {
|
||||
if (current == null
|
||||
|| current.getControlChar(Attributes.ControlChar.VMIN) != 0
|
||||
|
@ -81,8 +81,8 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
protected boolean focusTracking = false;
|
||||
private volatile boolean closing;
|
||||
|
||||
public AbstractWindowsTerminal(Writer writer, String name, String type, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
super(name, type, selectCharset(encoding, codepage), signalHandler);
|
||||
public AbstractWindowsTerminal(Writer writer, String name, String type, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
super(name, type, encoding, signalHandler);
|
||||
NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader();
|
||||
this.slaveInputPipe = reader.getWriter();
|
||||
this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding()));
|
||||
@ -116,35 +116,6 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal {
|
||||
}
|
||||
}
|
||||
|
||||
private static Charset selectCharset(Charset encoding, int codepage) {
|
||||
if (encoding != null) {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
if (codepage >= 0) {
|
||||
return getCodepageCharset(codepage);
|
||||
}
|
||||
|
||||
// Use UTF-8 as default
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
private static Charset getCodepageCharset(int codepage) {
|
||||
//http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
|
||||
if (codepage == UTF8_CODE_PAGE) {
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
String charsetMS = "ms" + codepage;
|
||||
if (Charset.isSupported(charsetMS)) {
|
||||
return Charset.forName(charsetMS);
|
||||
}
|
||||
String charsetCP = "cp" + codepage;
|
||||
if (Charset.isSupported(charsetCP)) {
|
||||
return Charset.forName(charsetCP);
|
||||
}
|
||||
return Charset.defaultCharset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignalHandler handle(Signal signal, SignalHandler handler) {
|
||||
SignalHandler prev = super.handle(signal, handler);
|
||||
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.impl;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
public class Diag {
|
||||
|
||||
public static void main(String[] args) {
|
||||
diag(System.out);
|
||||
}
|
||||
|
||||
static void diag(PrintStream out) {
|
||||
out.println("System properties");
|
||||
out.println("=================");
|
||||
out.println("os.name = " + System.getProperty("os.name"));
|
||||
out.println("OSTYPE = " + System.getenv("OSTYPE"));
|
||||
out.println("MSYSTEM = " + System.getenv("MSYSTEM"));
|
||||
out.println("PWD = " + System.getenv("PWD"));
|
||||
out.println("ConEmuPID = " + System.getenv("ConEmuPID"));
|
||||
out.println("WSL_DISTRO_NAME = " + System.getenv("WSL_DISTRO_NAME"));
|
||||
out.println("WSL_INTEROP = " + System.getenv("WSL_INTEROP"));
|
||||
out.println();
|
||||
|
||||
out.println("OSUtils");
|
||||
out.println("=================");
|
||||
out.println("IS_WINDOWS = " + OSUtils.IS_WINDOWS);
|
||||
out.println("IS_CYGWIN = " + OSUtils.IS_CYGWIN);
|
||||
out.println("IS_MSYSTEM = " + OSUtils.IS_MSYSTEM);
|
||||
out.println("IS_WSL = " + OSUtils.IS_WSL);
|
||||
out.println("IS_WSL1 = " + OSUtils.IS_WSL1);
|
||||
out.println("IS_WSL2 = " + OSUtils.IS_WSL2);
|
||||
out.println("IS_CONEMU = " + OSUtils.IS_CONEMU);
|
||||
out.println("IS_OSX = " + OSUtils.IS_OSX);
|
||||
out.println();
|
||||
|
||||
out.println("JnaSupport");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jna");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("JNA support not available: " + t);
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("JansiSupport");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("jansi");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("Jansi support not available: " + t);
|
||||
}
|
||||
out.println();
|
||||
|
||||
// Exec
|
||||
out.println("Exec Support");
|
||||
out.println("=================");
|
||||
try {
|
||||
TerminalProvider provider = TerminalProvider.load("exec");
|
||||
testProvider(out, provider);
|
||||
} catch (Throwable t) {
|
||||
out.println("Exec support not available: " + t);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
} 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));
|
||||
} catch (Throwable t2) {
|
||||
out.println("Unable to check stream names: " + t2);
|
||||
}
|
||||
try (Terminal terminal = provider.sysTerminal("diag", "xterm", false, StandardCharsets.UTF_8,
|
||||
false, Terminal.SignalHandler.SIG_DFL, false, TerminalProvider.Stream.Output, input -> input) ) {
|
||||
if (terminal != null) {
|
||||
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);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("The terminal seems to work: ");
|
||||
sb.append("terminal ").append(terminal.getClass().getName());
|
||||
if (terminal instanceof AbstractPosixTerminal) {
|
||||
sb.append(" with pty ").append(((AbstractPosixTerminal) terminal).getPty().getClass().getName());
|
||||
}
|
||||
out.println(sb);
|
||||
} catch (Throwable t3) {
|
||||
out.println("Unable to read from terminal: " + t3);
|
||||
t3.printStackTrace();
|
||||
} finally {
|
||||
terminal.setAttributes(attr);
|
||||
}
|
||||
} else {
|
||||
out.println("Not supported by provider");
|
||||
}
|
||||
} catch (Throwable t2) {
|
||||
out.println("Unable to open terminal: " + t2);
|
||||
t2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static <S> S load(Class<S> clazz) {
|
||||
return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,7 @@ import jdk.internal.org.jline.terminal.Attributes.InputFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
|
||||
import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
@ -34,20 +35,23 @@ import static jdk.internal.org.jline.utils.ExecHelper.exec;
|
||||
public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
private final String name;
|
||||
private final boolean system;
|
||||
private final TerminalProvider.Stream console;
|
||||
|
||||
public static Pty current() throws IOException {
|
||||
public static Pty current(TerminalProvider.Stream console) throws IOException {
|
||||
try {
|
||||
String result = exec(true, OSUtils.TTY_COMMAND);
|
||||
return new ExecPty(result.trim(), true);
|
||||
if (console != TerminalProvider.Stream.Output && console != TerminalProvider.Stream.Error) {
|
||||
throw new IllegalArgumentException("console should be Output or Error: " + console);
|
||||
}
|
||||
return new ExecPty(result.trim(), console);
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Not a tty", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected ExecPty(String name, boolean system) {
|
||||
protected ExecPty(String name, TerminalProvider.Stream console) {
|
||||
this.name = name;
|
||||
this.system = system;
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,16 +74,18 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
@Override
|
||||
protected InputStream doGetSlaveInput() throws IOException {
|
||||
return system
|
||||
return console != null
|
||||
? new FileInputStream(FileDescriptor.in)
|
||||
: new FileInputStream(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getSlaveOutput() throws IOException {
|
||||
return system
|
||||
return console == TerminalProvider.Stream.Output
|
||||
? new FileOutputStream(FileDescriptor.out)
|
||||
: new FileOutputStream(getName());
|
||||
: console == TerminalProvider.Stream.Error
|
||||
? new FileOutputStream(FileDescriptor.err)
|
||||
: new FileOutputStream(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -93,23 +99,11 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
List<String> commands = getFlagsToSet(attr, getAttr());
|
||||
if (!commands.isEmpty()) {
|
||||
commands.add(0, OSUtils.STTY_COMMAND);
|
||||
if (!system) {
|
||||
if (console == null) {
|
||||
commands.add(1, OSUtils.STTY_F_OPTION);
|
||||
commands.add(2, getName());
|
||||
}
|
||||
try {
|
||||
exec(system, commands.toArray(new String[commands.size()]));
|
||||
} catch (IOException e) {
|
||||
// Handle partial failures with GNU stty, see #97
|
||||
if (e.toString().contains("unable to perform all requested operations")) {
|
||||
commands = getFlagsToSet(attr, getAttr());
|
||||
if (!commands.isEmpty()) {
|
||||
throw new IOException("Could not set the following flags: " + String.join(", ", commands), e);
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
exec(console != null, commands.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +165,7 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
}
|
||||
|
||||
protected String doGetConfig() throws IOException {
|
||||
return system
|
||||
return console != null
|
||||
? exec(true, OSUtils.STTY_COMMAND, "-a")
|
||||
: exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-a");
|
||||
}
|
||||
@ -280,7 +274,7 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
@Override
|
||||
public void setSize(Size size) throws IOException {
|
||||
if (system) {
|
||||
if (console != null) {
|
||||
exec(true,
|
||||
OSUtils.STTY_COMMAND,
|
||||
"columns", Integer.toString(size.getColumns()),
|
||||
@ -296,7 +290,7 @@ public class ExecPty extends AbstractPty implements Pty {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExecPty[" + getName() + (system ? ", system]" : "]");
|
||||
return "ExecPty[" + getName() + (console != null ? ", system]" : "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.ClosedException;
|
||||
@ -143,10 +142,10 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
}
|
||||
}
|
||||
|
||||
private class InputStreamWrapper extends NonBlockingInputStream {
|
||||
private static class InputStreamWrapper extends NonBlockingInputStream {
|
||||
|
||||
private final NonBlockingInputStream in;
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
private volatile boolean closed;
|
||||
|
||||
protected InputStreamWrapper(NonBlockingInputStream in) {
|
||||
this.in = in;
|
||||
@ -154,7 +153,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
|
||||
@Override
|
||||
public int read(long timeout, boolean isPeek) throws IOException {
|
||||
if (closed.get()) {
|
||||
if (closed) {
|
||||
throw new ClosedException();
|
||||
}
|
||||
return in.read(timeout, isPeek);
|
||||
@ -162,7 +161,7 @@ public class PosixPtyTerminal extends AbstractPosixTerminal {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed.set(true);
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.utils.NonBlocking;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
@ -34,11 +35,12 @@ public class PosixSysTerminal extends AbstractPosixTerminal {
|
||||
protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
|
||||
protected final Task closer;
|
||||
|
||||
public PosixSysTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding,
|
||||
boolean nativeSignals, SignalHandler signalHandler) throws IOException {
|
||||
public PosixSysTerminal(String name, String type, Pty pty, Charset encoding,
|
||||
boolean nativeSignals, SignalHandler signalHandler,
|
||||
Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
super(name, type, pty, encoding, signalHandler);
|
||||
this.input = NonBlocking.nonBlocking(getName(), in);
|
||||
this.output = out;
|
||||
this.input = NonBlocking.nonBlocking(getName(), inputStreamWrapper.apply(pty.getSlaveInput()));
|
||||
this.output = pty.getSlaveOutput();
|
||||
this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
|
||||
this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
|
||||
parseInfoCmp();
|
||||
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.impl.exec;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.ExecPty;
|
||||
import jdk.internal.org.jline.terminal.impl.ExternalTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.ExecHelper;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
public class ExecTerminalProvider implements TerminalProvider
|
||||
{
|
||||
|
||||
public String name() {
|
||||
return "exec";
|
||||
}
|
||||
|
||||
public Pty current(Stream consoleStream) throws IOException {
|
||||
return ExecPty.current(consoleStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
return winSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
|
||||
} else {
|
||||
return posixSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
|
||||
}
|
||||
}
|
||||
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper ) throws IOException {
|
||||
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
|
||||
Pty pty = current(consoleStream);
|
||||
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
Pty pty = current(consoleStream);
|
||||
return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out,
|
||||
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Attributes attributes, Size size) throws IOException
|
||||
{
|
||||
return new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused, attributes, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSystemStream(Stream stream) {
|
||||
try {
|
||||
return isWindowsSystemStream(stream) || isPosixSystemStream(stream);
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWindowsSystemStream(Stream stream) {
|
||||
return systemStreamName( stream ) != null;
|
||||
}
|
||||
|
||||
public boolean isPosixSystemStream(Stream stream) {
|
||||
try {
|
||||
Process p = new ProcessBuilder(OSUtils.TEST_COMMAND, "-t", Integer.toString(stream.ordinal()))
|
||||
.inheritIO().start();
|
||||
return p.waitFor() == 0;
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String systemStreamName(Stream stream) {
|
||||
try {
|
||||
ProcessBuilder.Redirect input = stream == Stream.Input
|
||||
? ProcessBuilder.Redirect.INHERIT
|
||||
: getRedirect(stream == Stream.Output ? FileDescriptor.out : FileDescriptor.err);
|
||||
Process p = new ProcessBuilder(OSUtils.TTY_COMMAND).redirectInput(input).start();
|
||||
String result = ExecHelper.waitAndCapture(p);
|
||||
if (p.exitValue() == 0) {
|
||||
return result.trim();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ProcessBuilder.Redirect getRedirect(FileDescriptor fd) throws ReflectiveOperationException {
|
||||
// This is not really allowed, but this is the only way to redirect the output or error stream
|
||||
// to the input. This is definitely not something you'd usually want to do, but in the case of
|
||||
// the `tty` utility, it provides a way to get
|
||||
Class<?> rpi = Class.forName("java.lang.ProcessBuilder$RedirectPipeImpl");
|
||||
Constructor<?> cns = rpi.getDeclaredConstructor();
|
||||
cns.setAccessible(true);
|
||||
ProcessBuilder.Redirect input = (ProcessBuilder.Redirect) cns.newInstance();
|
||||
Field f = rpi.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
f.set(input, fd);
|
||||
return input;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.spi;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public interface JansiSupport {
|
||||
|
||||
Pty current() throws IOException;
|
||||
|
||||
Pty open(Attributes attributes, Size size) throws IOException;
|
||||
|
||||
Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException;
|
||||
|
||||
Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException;
|
||||
|
||||
boolean isWindowsConsole();
|
||||
|
||||
boolean isConsoleOutput();
|
||||
|
||||
boolean isConsoleInput();
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.spi;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface JnaSupport {
|
||||
|
||||
Pty current() throws IOException;
|
||||
|
||||
Pty open(Attributes attributes, Size size) throws IOException;
|
||||
|
||||
Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException;
|
||||
|
||||
Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException;
|
||||
|
||||
Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException;
|
||||
|
||||
boolean isWindowsConsole();
|
||||
|
||||
boolean isConsoleOutput();
|
||||
|
||||
boolean isConsoleInput();
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2022, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.exec.ExecTerminalProvider;
|
||||
|
||||
public interface TerminalProvider
|
||||
{
|
||||
|
||||
enum Stream {
|
||||
Input,
|
||||
Output,
|
||||
Error
|
||||
}
|
||||
|
||||
String name();
|
||||
|
||||
Terminal sysTerminal(String name, String type, boolean ansiPassThrough,
|
||||
Charset encoding, boolean nativeSignals,
|
||||
Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException;
|
||||
|
||||
Terminal newTerminal(String name, String type,
|
||||
InputStream masterInput, OutputStream masterOutput,
|
||||
Charset encoding, Terminal.SignalHandler signalHandler,
|
||||
boolean paused, Attributes attributes, Size size) throws IOException;
|
||||
|
||||
boolean isSystemStream(Stream stream);
|
||||
|
||||
String systemStreamName(Stream stream);
|
||||
|
||||
static TerminalProvider load(String name) throws IOException {
|
||||
switch (name) {
|
||||
case "exec": return new ExecTerminalProvider();
|
||||
case "jna": {
|
||||
try {
|
||||
return (TerminalProvider) Class.forName("jdk.internal.org.jline.terminal.impl.jna.JnaTerminalProvider").getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException t) {
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl == null) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
InputStream is = cl.getResourceAsStream( "META-INF/services/org/jline/terminal/provider/" + name);
|
||||
if (is != null) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(is);
|
||||
String className = props.getProperty("class");
|
||||
if (className == null) {
|
||||
throw new IOException("No class defined in terminal provider file " + name);
|
||||
}
|
||||
Class<?> clazz = cl.loadClass( className );
|
||||
return (TerminalProvider) clazz.getConstructor().newInstance();
|
||||
} catch ( Exception e ) {
|
||||
throw new IOException("Unable to load terminal provider " + name, e);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unable to find terminal provider " + name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -534,7 +534,7 @@ public class Colors {
|
||||
H = 0;
|
||||
return H;
|
||||
} else {
|
||||
throw new IllegalArgumentException("h outside assumed range 0..360: " + Double.toString(h));
|
||||
throw new IllegalArgumentException("h outside assumed range 0..360: " + h);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import java.io.Flushable;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Stack;
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
/**
|
||||
* Curses helper methods.
|
||||
@ -21,8 +21,8 @@ import java.util.Stack;
|
||||
*/
|
||||
public final class Curses {
|
||||
|
||||
private static Object[] sv = new Object[26];
|
||||
private static Object[] dv = new Object[26];
|
||||
private static final Object[] sv = new Object[26];
|
||||
private static final Object[] dv = new Object[26];
|
||||
|
||||
private static final int IFTE_NONE = 0;
|
||||
private static final int IFTE_IF = 1;
|
||||
@ -68,7 +68,7 @@ public final class Curses {
|
||||
int length = str.length();
|
||||
int ifte = IFTE_NONE;
|
||||
boolean exec = true;
|
||||
Stack<Object> stack = new Stack<>();
|
||||
ArrayDeque<Object> stack = new ArrayDeque<>();
|
||||
while (index < length) {
|
||||
char ch = str.charAt(index++);
|
||||
switch (ch) {
|
||||
@ -197,7 +197,7 @@ public final class Curses {
|
||||
int start = index;
|
||||
while (str.charAt(index++) != '}') ;
|
||||
if (exec) {
|
||||
int v = Integer.valueOf(str.substring(start, index - 1));
|
||||
int v = Integer.parseInt(str.substring(start, index - 1));
|
||||
stack.push(v);
|
||||
}
|
||||
break;
|
||||
@ -470,7 +470,7 @@ public final class Curses {
|
||||
} else if (pop instanceof Boolean) {
|
||||
return (Boolean) pop ? 1 : 0;
|
||||
} else {
|
||||
return Integer.valueOf(pop.toString());
|
||||
return Integer.parseInt(pop.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class Display {
|
||||
|
||||
int lineIndex = 0;
|
||||
int currentPos = 0;
|
||||
int numLines = Math.max(oldLines.size(), newLines.size());
|
||||
int numLines = Math.min(rows, Math.max(oldLines.size(), newLines.size()));
|
||||
boolean wrapNeeded = false;
|
||||
while (lineIndex < numLines) {
|
||||
AttributedString oldLine =
|
||||
|
@ -503,7 +503,7 @@ public final class InfoCmp {
|
||||
public String[] getNames() {
|
||||
return getCapabilitiesByName().entrySet().stream()
|
||||
.filter(e -> e.getValue() == this)
|
||||
.map(Map.Entry::getValue)
|
||||
.map(Map.Entry::getKey)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
|
@ -95,13 +95,9 @@ public class NonBlocking {
|
||||
|
||||
@Override
|
||||
public int read(long timeout, boolean isPeek) throws IOException {
|
||||
boolean isInfinite = (timeout <= 0L);
|
||||
while (!bytes.hasRemaining() && (isInfinite || timeout > 0L)) {
|
||||
long start = 0;
|
||||
if (!isInfinite) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
int c = reader.read(timeout);
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!bytes.hasRemaining() && !t.elapsed()) {
|
||||
int c = reader.read(t.timeout());
|
||||
if (c == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
@ -117,9 +113,6 @@ public class NonBlocking {
|
||||
encoder.encode(chars, bytes, false);
|
||||
bytes.flip();
|
||||
}
|
||||
if (!isInfinite) {
|
||||
timeout -= System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
if (bytes.hasRemaining()) {
|
||||
if (isPeek) {
|
||||
@ -151,21 +144,17 @@ public class NonBlocking {
|
||||
public NonBlockingInputStreamReader(NonBlockingInputStream input, CharsetDecoder decoder) {
|
||||
this.input = input;
|
||||
this.decoder = decoder;
|
||||
this.bytes = ByteBuffer.allocate(4);
|
||||
this.chars = CharBuffer.allocate(2);
|
||||
this.bytes = ByteBuffer.allocate(2048);
|
||||
this.chars = CharBuffer.allocate(1024);
|
||||
this.bytes.limit(0);
|
||||
this.chars.limit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int read(long timeout, boolean isPeek) throws IOException {
|
||||
boolean isInfinite = (timeout <= 0L);
|
||||
while (!chars.hasRemaining() && (isInfinite || timeout > 0L)) {
|
||||
long start = 0;
|
||||
if (!isInfinite) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
int b = input.read(timeout);
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!chars.hasRemaining() && !t.elapsed()) {
|
||||
int b = input.read(t.timeout());
|
||||
if (b == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
@ -181,10 +170,6 @@ public class NonBlocking {
|
||||
decoder.decode(bytes, chars, false);
|
||||
chars.flip();
|
||||
}
|
||||
|
||||
if (!isInfinite) {
|
||||
timeout -= System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
if (chars.hasRemaining()) {
|
||||
if (isPeek) {
|
||||
@ -198,46 +183,37 @@ public class NonBlocking {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBuffered(char[] b) throws IOException {
|
||||
public int readBuffered(char[] b, int off, int len, long timeout) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (b.length == 0) {
|
||||
} else if (off < 0 || len < 0 || off + len < b.length) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
} else if (chars.hasRemaining()) {
|
||||
int r = Math.min(len, chars.remaining());
|
||||
chars.get(b, off, r);
|
||||
return r;
|
||||
} else {
|
||||
if (chars.hasRemaining()) {
|
||||
int r = Math.min(b.length, chars.remaining());
|
||||
chars.get(b);
|
||||
return r;
|
||||
} else {
|
||||
byte[] buf = new byte[b.length];
|
||||
int l = input.readBuffered(buf);
|
||||
if (l < 0) {
|
||||
return l;
|
||||
} else {
|
||||
ByteBuffer currentBytes;
|
||||
if (bytes.hasRemaining()) {
|
||||
int transfer = bytes.remaining();
|
||||
byte[] newBuf = new byte[l + transfer];
|
||||
bytes.get(newBuf, 0, transfer);
|
||||
System.arraycopy(buf, 0, newBuf, transfer, l);
|
||||
currentBytes = ByteBuffer.wrap(newBuf);
|
||||
bytes.position(0);
|
||||
bytes.limit(0);
|
||||
} else {
|
||||
currentBytes = ByteBuffer.wrap(buf, 0, l);
|
||||
}
|
||||
CharBuffer chars = CharBuffer.wrap(b);
|
||||
decoder.decode(currentBytes, chars, false);
|
||||
chars.flip();
|
||||
if (currentBytes.hasRemaining()) {
|
||||
int pos = bytes.position();
|
||||
bytes.limit(bytes.limit() + currentBytes.remaining());
|
||||
bytes.put(currentBytes);
|
||||
bytes.position(pos);
|
||||
}
|
||||
return chars.remaining();
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!chars.hasRemaining() && !t.elapsed()) {
|
||||
if (!bytes.hasRemaining()) {
|
||||
bytes.position(0);
|
||||
bytes.limit(0);
|
||||
}
|
||||
int nb = input.readBuffered(bytes.array(), bytes.limit(),
|
||||
bytes.capacity() - bytes.limit(), t.timeout());
|
||||
if (nb < 0) {
|
||||
return nb;
|
||||
}
|
||||
bytes.limit(bytes.limit() + nb);
|
||||
chars.clear();
|
||||
decoder.decode(bytes, chars, false);
|
||||
chars.flip();
|
||||
}
|
||||
int nb = Math.min(len, chars.remaining());
|
||||
chars.get(b, off, nb);
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,12 +79,34 @@ public abstract class NonBlockingInputStream extends InputStream {
|
||||
}
|
||||
|
||||
public int readBuffered(byte[] b) throws IOException {
|
||||
return readBuffered(b, 0L);
|
||||
}
|
||||
|
||||
public int readBuffered(byte[] b, long timeout) throws IOException {
|
||||
return readBuffered(b, 0, b.length, timeout);
|
||||
}
|
||||
|
||||
public int readBuffered(byte[] b, int off, int len, long timeout) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (b.length == 0) {
|
||||
} else if (off < 0 || len < 0 || off + len < b.length) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return super.read(b, 0, b.length);
|
||||
Timeout t = new Timeout(timeout);
|
||||
int nb = 0;
|
||||
while (!t.elapsed()) {
|
||||
int r = read(nb > 0 ? 1 : t.timeout());
|
||||
if (r < 0) {
|
||||
return nb > 0 ? nb : r;
|
||||
}
|
||||
b[off + nb++] = (byte) r;
|
||||
if (nb >= len || t.isInfinite()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,20 +123,17 @@ public class NonBlockingInputStreamImpl
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
boolean isInfinite = (timeout <= 0L);
|
||||
|
||||
/*
|
||||
* So the thread is currently doing the reading for us. So
|
||||
* now we play the waiting game.
|
||||
*/
|
||||
while (isInfinite || timeout > 0L) {
|
||||
long start = System.currentTimeMillis ();
|
||||
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!t.elapsed()) {
|
||||
try {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
wait(timeout);
|
||||
wait(t.timeout());
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
exception = (IOException) new InterruptedIOException().initCause(e);
|
||||
@ -155,10 +152,6 @@ public class NonBlockingInputStreamImpl
|
||||
assert exception == null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isInfinite) {
|
||||
timeout -= System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,24 +45,17 @@ public class NonBlockingPumpInputStream extends NonBlockingInputStream {
|
||||
}
|
||||
|
||||
private int wait(ByteBuffer buffer, long timeout) throws IOException {
|
||||
boolean isInfinite = (timeout <= 0L);
|
||||
long end = 0;
|
||||
if (!isInfinite) {
|
||||
end = System.currentTimeMillis() + timeout;
|
||||
}
|
||||
while (!closed && !buffer.hasRemaining() && (isInfinite || timeout > 0L)) {
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!closed && !buffer.hasRemaining() && !t.elapsed()) {
|
||||
// Wake up waiting readers/writers
|
||||
notifyAll();
|
||||
try {
|
||||
wait(timeout);
|
||||
wait(t.timeout());
|
||||
checkIoException();
|
||||
} catch (InterruptedException e) {
|
||||
checkIoException();
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
if (!isInfinite) {
|
||||
timeout = end - System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
return buffer.hasRemaining()
|
||||
? 0
|
||||
@ -107,17 +100,25 @@ public class NonBlockingPumpInputStream extends NonBlockingInputStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int readBuffered(byte[] b) throws IOException {
|
||||
checkIoException();
|
||||
int res = wait(readBuffer, 0L);
|
||||
if (res >= 0) {
|
||||
res = 0;
|
||||
while (res < b.length && readBuffer.hasRemaining()) {
|
||||
b[res++] = (byte) (readBuffer.get() & 0x00FF);
|
||||
public synchronized int readBuffered(byte[] b, int off, int len, long timeout) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (off < 0 || len < 0 || off + len < b.length) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
checkIoException();
|
||||
int res = wait(readBuffer, timeout);
|
||||
if (res >= 0) {
|
||||
res = 0;
|
||||
while (res < len && readBuffer.hasRemaining()) {
|
||||
b[off + res++] = (byte) (readBuffer.get() & 0x00FF);
|
||||
}
|
||||
}
|
||||
rewind(readBuffer, writeBuffer);
|
||||
return res;
|
||||
}
|
||||
rewind(readBuffer, writeBuffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
public synchronized void setIoException(IOException exception) {
|
||||
|
@ -106,10 +106,12 @@ public class NonBlockingPumpReader extends NonBlockingReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBuffered(char[] b) throws IOException {
|
||||
public int readBuffered(char[] b, int off, int len, long timeout) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (b.length == 0) {
|
||||
} else if (off < 0 || len < 0 || off + len < b.length) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
final ReentrantLock lock = this.lock;
|
||||
@ -117,7 +119,13 @@ public class NonBlockingPumpReader extends NonBlockingReader {
|
||||
try {
|
||||
if (!closed && count == 0) {
|
||||
try {
|
||||
notEmpty.await();
|
||||
if (timeout > 0) {
|
||||
if (!notEmpty.await(timeout, TimeUnit.MILLISECONDS)) {
|
||||
throw new IOException( "Timeout reading" );
|
||||
}
|
||||
} else {
|
||||
notEmpty.await();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw (IOException) new InterruptedIOException().initCause(e);
|
||||
}
|
||||
@ -127,9 +135,9 @@ public class NonBlockingPumpReader extends NonBlockingReader {
|
||||
} else if (count == 0) {
|
||||
return READ_EXPIRED;
|
||||
} else {
|
||||
int r = Math.min(b.length, count);
|
||||
int r = Math.min(len, count);
|
||||
for (int i = 0; i < r; i++) {
|
||||
b[i] = buffer[read++];
|
||||
b[off + i] = buffer[read++];
|
||||
if (read == buffer.length) {
|
||||
read = 0;
|
||||
}
|
||||
|
@ -85,7 +85,15 @@ public abstract class NonBlockingReader extends Reader {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public abstract int readBuffered(char[] b) throws IOException;
|
||||
public int readBuffered(char[] b) throws IOException {
|
||||
return readBuffered(b, 0L);
|
||||
}
|
||||
|
||||
public int readBuffered(char[] b, long timeout) throws IOException {
|
||||
return readBuffered(b, 0, b.length, timeout);
|
||||
}
|
||||
|
||||
public abstract int readBuffered(char[] b, int off, int len, long timeout) throws IOException;
|
||||
|
||||
public int available() {
|
||||
return 0;
|
||||
|
@ -91,10 +91,12 @@ public class NonBlockingReaderImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBuffered(char[] b) throws IOException {
|
||||
public int readBuffered(char[] b, int off, int len, long timeout) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (b.length == 0) {
|
||||
} else if (off < 0 || len < 0 || off + len < b.length) {
|
||||
throw new IllegalArgumentException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
} else if (exception != null) {
|
||||
assert ch == READ_EXPIRED;
|
||||
@ -105,15 +107,16 @@ public class NonBlockingReaderImpl
|
||||
b[0] = (char) ch;
|
||||
ch = READ_EXPIRED;
|
||||
return 1;
|
||||
} else if (!threadIsReading) {
|
||||
return in.read(b);
|
||||
} else if (!threadIsReading && timeout <= 0) {
|
||||
return in.read(b, off, len);
|
||||
} else {
|
||||
int c = read(-1, false);
|
||||
// TODO: rework implementation to read as much as possible
|
||||
int c = read(timeout, false);
|
||||
if (c >= 0) {
|
||||
b[0] = (char) c;
|
||||
b[off] = (char) c;
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,20 +161,17 @@ public class NonBlockingReaderImpl
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
boolean isInfinite = (timeout <= 0L);
|
||||
|
||||
/*
|
||||
* So the thread is currently doing the reading for us. So
|
||||
* now we play the waiting game.
|
||||
*/
|
||||
while (isInfinite || timeout > 0L) {
|
||||
long start = System.currentTimeMillis ();
|
||||
|
||||
Timeout t = new Timeout(timeout);
|
||||
while (!t.elapsed()) {
|
||||
try {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
wait(timeout);
|
||||
wait(t.timeout());
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
exception = (IOException) new InterruptedIOException().initCause(e);
|
||||
@ -190,10 +190,6 @@ public class NonBlockingReaderImpl
|
||||
assert exception == null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isInfinite) {
|
||||
timeout -= System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,12 @@ public class OSUtils {
|
||||
&& (System.getenv("MSYSTEM").startsWith("MINGW")
|
||||
|| System.getenv("MSYSTEM").equals("MSYS"));
|
||||
|
||||
public static final boolean IS_WSL = System.getenv("WSL_DISTRO_NAME") != null;
|
||||
|
||||
public static final boolean IS_WSL1 = IS_WSL && System.getenv("WSL_INTEROP") == null;
|
||||
|
||||
public static final boolean IS_WSL2 = IS_WSL && !IS_WSL1;
|
||||
|
||||
public static final boolean IS_CONEMU = IS_WINDOWS
|
||||
&& System.getenv("ConEmuPID") != null;
|
||||
|
||||
@ -38,17 +44,20 @@ public class OSUtils {
|
||||
public static String STTY_COMMAND;
|
||||
public static String STTY_F_OPTION;
|
||||
public static String INFOCMP_COMMAND;
|
||||
public static String TEST_COMMAND;
|
||||
|
||||
static {
|
||||
String tty;
|
||||
String stty;
|
||||
String sttyfopt;
|
||||
String infocmp;
|
||||
String test;
|
||||
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
|
||||
tty = "tty.exe";
|
||||
stty = "stty.exe";
|
||||
tty = null;
|
||||
stty = null;
|
||||
sttyfopt = null;
|
||||
infocmp = "infocmp.exe";
|
||||
infocmp = null;
|
||||
test = null;
|
||||
String path = System.getenv("PATH");
|
||||
if (path != null) {
|
||||
String[] paths = path.split(";");
|
||||
@ -62,23 +71,35 @@ public class OSUtils {
|
||||
if (infocmp == null && new File(p, "infocmp.exe").exists()) {
|
||||
infocmp = new File(p, "infocmp.exe").getAbsolutePath();
|
||||
}
|
||||
if (test == null && new File(p, "test.exe").exists()) {
|
||||
test = new File(p, "test.exe").getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tty == null) {
|
||||
tty = "tty.exe";
|
||||
}
|
||||
if (stty == null) {
|
||||
stty = "stty.exe";
|
||||
}
|
||||
if (infocmp == null) {
|
||||
infocmp = "infocmp.exe";
|
||||
}
|
||||
if (test == null) {
|
||||
test = "test.exe";
|
||||
}
|
||||
} else {
|
||||
tty = "tty";
|
||||
stty = "stty";
|
||||
stty = IS_OSX ? "/bin/stty" : "stty";
|
||||
sttyfopt = IS_OSX ? "-f" : "-F";
|
||||
infocmp = "infocmp";
|
||||
if (IS_OSX) {
|
||||
sttyfopt = "-f";
|
||||
}
|
||||
else {
|
||||
sttyfopt = "-F";
|
||||
}
|
||||
test = "/bin/test";
|
||||
}
|
||||
TTY_COMMAND = tty;
|
||||
STTY_COMMAND = stty;
|
||||
STTY_F_OPTION = sttyfopt;
|
||||
INFOCMP_COMMAND = infocmp;
|
||||
TEST_COMMAND = test;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class PumpReader extends Reader {
|
||||
}
|
||||
|
||||
public PumpReader(int bufferSize) {
|
||||
char[] buf = new char[bufferSize];
|
||||
char[] buf = new char[Math.max(bufferSize, 2)];
|
||||
this.readBuffer = CharBuffer.wrap(buf);
|
||||
this.writeBuffer = CharBuffer.wrap(buf);
|
||||
this.writer = new Writer(this);
|
||||
@ -53,12 +53,52 @@ public class PumpReader extends Reader {
|
||||
return new InputStream(this, charset);
|
||||
}
|
||||
|
||||
private boolean wait(CharBuffer buffer) throws InterruptedIOException {
|
||||
if (closed) {
|
||||
return false;
|
||||
/**
|
||||
* Blocks until more input is available, even if {@link #readBuffer} already
|
||||
* contains some chars; or until the reader is closed.
|
||||
*
|
||||
* @return true if more input is available, false if no additional input is
|
||||
* available and the reader is closed
|
||||
* @throws InterruptedIOException If {@link #wait()} is interrupted
|
||||
*/
|
||||
private boolean waitForMoreInput() throws InterruptedIOException {
|
||||
if (!writeBuffer.hasRemaining()) {
|
||||
throw new AssertionError("No space in write buffer");
|
||||
}
|
||||
|
||||
int oldRemaining = readBuffer.remaining();
|
||||
|
||||
do {
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wake up waiting writers
|
||||
notifyAll();
|
||||
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
} while (readBuffer.remaining() <= oldRemaining);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until {@code buffer.hasRemaining() == true}, or it is false and
|
||||
* the reader is {@link #closed}.
|
||||
*
|
||||
* @return true if {@code buffer.hasRemaining() == true}; false otherwise
|
||||
* when reader is closed
|
||||
*/
|
||||
private boolean wait(CharBuffer buffer) throws InterruptedIOException {
|
||||
while (!buffer.hasRemaining()) {
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wake up waiting readers/writers
|
||||
notifyAll();
|
||||
|
||||
@ -67,19 +107,15 @@ public class PumpReader extends Reader {
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until more input is available or the reader is closed.
|
||||
* Blocks until input is available or the reader is closed.
|
||||
*
|
||||
* @return true if more input is available, false if the reader is closed
|
||||
* @return true if input is available, false if no input is available and the reader is closed
|
||||
* @throws InterruptedIOException If {@link #wait()} is interrupted
|
||||
*/
|
||||
private boolean waitForInput() throws InterruptedIOException {
|
||||
@ -94,7 +130,8 @@ public class PumpReader extends Reader {
|
||||
* @throws ClosedException If the reader was closed
|
||||
*/
|
||||
private void waitForBufferSpace() throws InterruptedIOException, ClosedException {
|
||||
if (!wait(writeBuffer)) {
|
||||
// Check `closed` to throw even if writer buffer has space available
|
||||
if (!wait(writeBuffer) || closed) {
|
||||
throw new ClosedException();
|
||||
}
|
||||
}
|
||||
@ -122,7 +159,9 @@ public class PumpReader extends Reader {
|
||||
* @return If more input is available
|
||||
*/
|
||||
private boolean rewindReadBuffer() {
|
||||
return rewind(readBuffer, writeBuffer) && readBuffer.hasRemaining();
|
||||
boolean rw = rewind(readBuffer, writeBuffer) && readBuffer.hasRemaining();
|
||||
notifyAll();
|
||||
return rw;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,6 +170,7 @@ public class PumpReader extends Reader {
|
||||
*/
|
||||
private void rewindWriteBuffer() {
|
||||
rewind(writeBuffer, readBuffer);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -202,10 +242,33 @@ public class PumpReader extends Reader {
|
||||
}
|
||||
|
||||
private void encodeBytes(CharsetEncoder encoder, ByteBuffer output) throws IOException {
|
||||
int oldPos = output.position();
|
||||
CoderResult result = encoder.encode(readBuffer, output, false);
|
||||
if (rewindReadBuffer() && result.isUnderflow()) {
|
||||
encoder.encode(readBuffer, output, false);
|
||||
int encodedCount = output.position() - oldPos;
|
||||
|
||||
if (result.isUnderflow()) {
|
||||
boolean hasMoreInput = rewindReadBuffer();
|
||||
boolean reachedEndOfInput = false;
|
||||
|
||||
// If encoding did not make any progress must block for more input
|
||||
if (encodedCount == 0 && !hasMoreInput) {
|
||||
reachedEndOfInput = !waitForMoreInput();
|
||||
}
|
||||
|
||||
result = encoder.encode(readBuffer, output, reachedEndOfInput);
|
||||
if (result.isError()) {
|
||||
result.throwException();
|
||||
}
|
||||
if (!reachedEndOfInput && output.position() - oldPos == 0) {
|
||||
throw new AssertionError("Failed to encode any chars");
|
||||
}
|
||||
rewindReadBuffer();
|
||||
} else if (result.isOverflow()) {
|
||||
if (encodedCount == 0) {
|
||||
throw new AssertionError("Output buffer has not enough space");
|
||||
}
|
||||
} else {
|
||||
result.throwException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +397,7 @@ public class PumpReader extends Reader {
|
||||
this.encoder = charset.newEncoder()
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE)
|
||||
.onMalformedInput(CodingErrorAction.REPLACE);
|
||||
this.buffer = ByteBuffer.allocate((int) Math.ceil(encoder.maxBytesPerChar()));
|
||||
this.buffer = ByteBuffer.allocate((int) Math.ceil(encoder.maxBytesPerChar() * 2));
|
||||
|
||||
// No input available after initialization
|
||||
buffer.limit(0);
|
||||
|
@ -241,7 +241,7 @@ public class StyleResolver {
|
||||
if (spec.length() == 1) {
|
||||
// log.warning("Invalid style-reference; missing discriminator: " + spec);
|
||||
} else {
|
||||
String name = spec.substring(1, spec.length());
|
||||
String name = spec.substring(1);
|
||||
String resolvedSpec = source.apply(name);
|
||||
if (resolvedSpec != null) {
|
||||
return apply(style, resolvedSpec);
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2018, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.utils;
|
||||
|
||||
/**
|
||||
* Helper class ti use during I/O operations with an eventual timeout.
|
||||
*/
|
||||
public class Timeout {
|
||||
|
||||
private final long timeout;
|
||||
private long cur = 0;
|
||||
private long end = Long.MAX_VALUE;
|
||||
|
||||
public Timeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public boolean isInfinite() {
|
||||
return timeout <= 0;
|
||||
}
|
||||
|
||||
public boolean isFinite() {
|
||||
return timeout > 0;
|
||||
}
|
||||
|
||||
public boolean elapsed() {
|
||||
if (timeout > 0) {
|
||||
cur = System.currentTimeMillis();
|
||||
if (end == Long.MAX_VALUE) {
|
||||
end = cur + timeout;
|
||||
}
|
||||
return cur >= end;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long timeout() {
|
||||
return timeout > 0 ? Math.max(1, end - cur) : timeout;
|
||||
}
|
||||
|
||||
}
|
@ -70,6 +70,7 @@ public final class WCWidth {
|
||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
|
||||
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
|
||||
(ucs >= 0x1f000 && ucs <= 0x1feee) ||
|
||||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
|
||||
(ucs >= 0x30000 && ucs <= 0x3fffd))) ? 1 : 0);
|
||||
}
|
||||
@ -123,8 +124,8 @@ public final class WCWidth {
|
||||
new Interval( 0x10A01, 0x10A03 ), new Interval( 0x10A05, 0x10A06 ), new Interval( 0x10A0C, 0x10A0F ),
|
||||
new Interval( 0x10A38, 0x10A3A ), new Interval( 0x10A3F, 0x10A3F ), new Interval( 0x1D167, 0x1D169 ),
|
||||
new Interval( 0x1D173, 0x1D182 ), new Interval( 0x1D185, 0x1D18B ), new Interval( 0x1D1AA, 0x1D1AD ),
|
||||
new Interval( 0x1D242, 0x1D244 ), new Interval( 0xE0001, 0xE0001 ), new Interval( 0xE0020, 0xE007F ),
|
||||
new Interval( 0xE0100, 0xE01EF )
|
||||
new Interval( 0x1D242, 0x1D244 ), new Interval( 0x1F3FB, 0x1F3FF ), new Interval( 0xE0001, 0xE0001 ),
|
||||
new Interval( 0xE0020, 0xE007F ), new Interval( 0xE0100, 0xE01EF )
|
||||
};
|
||||
|
||||
private static class Interval {
|
||||
|
@ -2,7 +2,7 @@ windows-vtp|windows with virtual terminal processing,
|
||||
am, mc5i, mir, msgr,
|
||||
colors#256, cols#80, it#8, lines#24, ncv#3, pairs#64,
|
||||
bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, clear=\E[H\E[J,
|
||||
cr=^M, cub=\E[%p1%dD, cub1=\E[D, cud=\E[%p1%dB, cud1=\E[B,
|
||||
cr=^M, cub=\E[%p1%dD, cub1=\E[D, cud=\E[%p1%dB, cud1=\n,
|
||||
cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH,
|
||||
cuu=\E[%p1%dA, cuu1=\E[A,
|
||||
il=\E[%p1%dL, il1=\E[L,
|
||||
|
@ -48,8 +48,6 @@ module jdk.internal.le {
|
||||
exports jdk.internal.org.jline.terminal.spi to
|
||||
jdk.jshell;
|
||||
|
||||
uses jdk.internal.org.jline.terminal.spi.JnaSupport;
|
||||
|
||||
// Console
|
||||
provides jdk.internal.io.JdkConsoleProvider with
|
||||
jdk.internal.org.jline.JdkConsoleProviderImpl;
|
||||
|
@ -1,4 +1,4 @@
|
||||
## JLine v3.20.0
|
||||
## JLine v3.22.0
|
||||
|
||||
### JLine License
|
||||
<pre>
|
||||
@ -41,10 +41,10 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
4th Party Dependency
|
||||
=============
|
||||
org.fusesource.jansi version 1.17.1
|
||||
org.apache.sshd 2.1 to 3
|
||||
org.apache.felix.gogo.runtime 1.1.2
|
||||
org.apache.felix.gogo.jline 1.1.4
|
||||
org.fusesource.jansi version 2.4.0
|
||||
org.apache.sshd 2.9.2
|
||||
org.apache.felix.gogo.runtime 1.1.6
|
||||
org.apache.felix.gogo.jline 1.1.8
|
||||
=============
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
@ -262,7 +262,7 @@ slf4j
|
||||
SLF4J source code and binaries are distributed under the MIT license.
|
||||
|
||||
|
||||
Copyright (c) 2004-2017 QOS.ch
|
||||
Copyright (c) 2004-2023 QOS.ch
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.impl.jna;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.jna.win.JnaWinSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.JnaSupport;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class JnaSupportImpl implements JnaSupport {
|
||||
@Override
|
||||
public Pty current() throws IOException {
|
||||
// return JnaNativePty.current();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pty open(Attributes attributes, Size size) throws IOException {
|
||||
// return JnaNativePty.open(attributes, size);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException {
|
||||
return winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException {
|
||||
return winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, input -> input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
return JnaWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, inputStreamWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWindowsConsole() {
|
||||
return JnaWinSysTerminal.isWindowsConsole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsoleOutput() {
|
||||
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
|
||||
throw new UnsupportedOperationException();
|
||||
} else if (OSUtils.IS_WINDOWS) {
|
||||
return JnaWinSysTerminal.isConsoleOutput();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsoleInput() {
|
||||
if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
|
||||
throw new UnsupportedOperationException();
|
||||
} else if (OSUtils.IS_WINDOWS) {
|
||||
return JnaWinSysTerminal.isConsoleInput();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
*
|
||||
* 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 jdk.internal.org.jline.terminal.impl.jna;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixPtyTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.impl.jna.win.JnaWinSysTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.terminal.spi.Pty;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class JnaTerminalProvider implements TerminalProvider
|
||||
{
|
||||
@Override
|
||||
public String name() {
|
||||
return "jna";
|
||||
}
|
||||
|
||||
// public Pty current(TerminalProvider.Stream console) throws IOException {
|
||||
// return JnaNativePty.current(console);
|
||||
// }
|
||||
//
|
||||
// public Pty open(Attributes attributes, Size size) throws IOException {
|
||||
// return JnaNativePty.open(attributes, size);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Terminal sysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
return winSysTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, consoleStream, inputStreamWrapper );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Stream console, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
return JnaWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, console, inputStreamWrapper);
|
||||
}
|
||||
|
||||
// public Terminal posixSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding,
|
||||
// boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
// Stream consoleStream) throws IOException {
|
||||
// Pty pty = current(consoleStream);
|
||||
// return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Terminal newTerminal(String name, String type, InputStream in, OutputStream out,
|
||||
Charset encoding, Terminal.SignalHandler signalHandler, boolean paused,
|
||||
Attributes attributes, Size size) throws IOException
|
||||
{
|
||||
// Pty pty = open(attributes, size);
|
||||
// return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSystemStream(Stream stream) {
|
||||
try {
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
return isWindowsSystemStream(stream);
|
||||
} else {
|
||||
// return isPosixSystemStream(stream);
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWindowsSystemStream(Stream stream) {
|
||||
return JnaWinSysTerminal.isWindowsSystemStream(stream);
|
||||
}
|
||||
|
||||
// public boolean isPosixSystemStream(Stream stream) {
|
||||
// return JnaNativePty.isPosixSystemStream(stream);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String systemStreamName(Stream stream) {
|
||||
// if (OSUtils.IS_WINDOWS) {
|
||||
return null;
|
||||
// } else {
|
||||
// return JnaNativePty.posixSystemStreamName(stream);
|
||||
// }
|
||||
}
|
||||
}
|
@ -17,17 +17,17 @@ import java.io.IOException;
|
||||
|
||||
class JnaWinConsoleWriter extends AbstractWindowsConsoleWriter {
|
||||
|
||||
private final Pointer consoleHandle;
|
||||
private final Pointer console;
|
||||
private final IntByReference writtenChars = new IntByReference();
|
||||
|
||||
JnaWinConsoleWriter(Pointer consoleHandle) {
|
||||
this.consoleHandle = consoleHandle;
|
||||
JnaWinConsoleWriter(Pointer console) {
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeConsole(char[] text, int len) throws IOException {
|
||||
try {
|
||||
Kernel32.INSTANCE.WriteConsoleW(this.consoleHandle, text, len, this.writtenChars, null);
|
||||
Kernel32.INSTANCE.WriteConsoleW(this.console, text, len, this.writtenChars, null);
|
||||
} catch (LastErrorException e) {
|
||||
throw new IOException("Failed to write to console", e);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2019, the original author or authors.
|
||||
* Copyright (c) 2002-2020, the original author or authors.
|
||||
*
|
||||
* This software is distributable under the BSD license. See the terms of the
|
||||
* BSD license in the documentation provided with this software.
|
||||
@ -19,11 +19,10 @@ import java.util.function.IntConsumer;
|
||||
//import com.sun.jna.LastErrorException;
|
||||
//import com.sun.jna.Pointer;
|
||||
//import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
import jdk.internal.org.jline.terminal.Cursor;
|
||||
import jdk.internal.org.jline.terminal.Size;
|
||||
import jdk.internal.org.jline.terminal.Terminal;
|
||||
import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
import jdk.internal.org.jline.utils.InfoCmp;
|
||||
import jdk.internal.org.jline.utils.OSUtils;
|
||||
|
||||
@ -31,38 +30,50 @@ public class JnaWinSysTerminal extends AbstractWindowsTerminal {
|
||||
|
||||
private static final Pointer consoleIn = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_INPUT_HANDLE);
|
||||
private static final Pointer consoleOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
|
||||
private static final Pointer consoleErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE);
|
||||
|
||||
public static JnaWinSysTerminal createTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
public static JnaWinSysTerminal createTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, boolean nativeSignals, SignalHandler signalHandler, boolean paused, TerminalProvider.Stream consoleStream, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
Pointer console;
|
||||
switch (consoleStream) {
|
||||
case Output:
|
||||
console = JnaWinSysTerminal.consoleOut;
|
||||
break;
|
||||
case Error:
|
||||
console = JnaWinSysTerminal.consoleErr;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupport stream for console: " + consoleStream);
|
||||
}
|
||||
Writer writer;
|
||||
if (ansiPassThrough) {
|
||||
if (type == null) {
|
||||
type = OSUtils.IS_CONEMU ? TYPE_WINDOWS_CONEMU : TYPE_WINDOWS;
|
||||
}
|
||||
writer = new JnaWinConsoleWriter(consoleOut);
|
||||
writer = new JnaWinConsoleWriter(console);
|
||||
} else {
|
||||
IntByReference mode = new IntByReference();
|
||||
Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
|
||||
Kernel32.INSTANCE.GetConsoleMode(console, mode);
|
||||
try {
|
||||
Kernel32.INSTANCE.SetConsoleMode(consoleOut, mode.getValue() | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
Kernel32.INSTANCE.SetConsoleMode(console, mode.getValue() | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
if (type == null) {
|
||||
type = TYPE_WINDOWS_VTP;
|
||||
}
|
||||
writer = new JnaWinConsoleWriter(consoleOut);
|
||||
writer = new JnaWinConsoleWriter(console);
|
||||
} catch (LastErrorException e) {
|
||||
if (OSUtils.IS_CONEMU) {
|
||||
if (type == null) {
|
||||
type = TYPE_WINDOWS_CONEMU;
|
||||
}
|
||||
writer = new JnaWinConsoleWriter(consoleOut);
|
||||
writer = new JnaWinConsoleWriter(console);
|
||||
} else {
|
||||
if (type == null) {
|
||||
type = TYPE_WINDOWS;
|
||||
}
|
||||
writer = new WindowsAnsiWriter(new BufferedWriter(new JnaWinConsoleWriter(consoleOut)), consoleOut);
|
||||
writer = new WindowsAnsiWriter(new BufferedWriter(new JnaWinConsoleWriter(console)), console);
|
||||
}
|
||||
}
|
||||
}
|
||||
JnaWinSysTerminal terminal = new JnaWinSysTerminal(writer, name, type, encoding, codepage, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
JnaWinSysTerminal terminal = new JnaWinSysTerminal(writer, name, type, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
// Start input pump thread
|
||||
if (!paused) {
|
||||
terminal.resume();
|
||||
@ -70,39 +81,26 @@ public class JnaWinSysTerminal extends AbstractWindowsTerminal {
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public static boolean isWindowsConsole() {
|
||||
public static boolean isWindowsSystemStream(TerminalProvider.Stream stream) {
|
||||
try {
|
||||
IntByReference mode = new IntByReference();
|
||||
Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
|
||||
Kernel32.INSTANCE.GetConsoleMode(consoleIn, mode);
|
||||
Pointer console;
|
||||
switch (stream) {
|
||||
case Input: console = consoleIn; break;
|
||||
case Output: console = consoleOut; break;
|
||||
case Error: console = consoleErr; break;
|
||||
default: return false;
|
||||
}
|
||||
Kernel32.INSTANCE.GetConsoleMode(console, mode);
|
||||
return true;
|
||||
} catch (LastErrorException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isConsoleOutput() {
|
||||
try {
|
||||
IntByReference mode = new IntByReference();
|
||||
Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
|
||||
return true;
|
||||
} catch (LastErrorException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isConsoleInput() {
|
||||
try {
|
||||
IntByReference mode = new IntByReference();
|
||||
Kernel32.INSTANCE.GetConsoleMode(consoleIn, mode);
|
||||
return true;
|
||||
} catch (LastErrorException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JnaWinSysTerminal(Writer writer, String name, String type, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
super(writer, name, type, encoding, codepage, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
JnaWinSysTerminal(Writer writer, String name, String type, Charset encoding, boolean nativeSignals, SignalHandler signalHandler,
|
||||
Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
|
||||
super(writer, name, type, encoding, nativeSignals, signalHandler, inputStreamWrapper);
|
||||
strings.put(InfoCmp.Capability.key_mouse, "\\E[M");
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
BACKGROUND_WHITE,
|
||||
};
|
||||
|
||||
private static final int MAX_ESCAPE_SEQUENCE_LENGTH = 100;
|
||||
private final static int MAX_ESCAPE_SEQUENCE_LENGTH = 100;
|
||||
|
||||
private final Pointer console;
|
||||
|
||||
@ -93,7 +93,7 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
private void getConsoleInfo() throws IOException {
|
||||
out.flush();
|
||||
Kernel32.INSTANCE.GetConsoleScreenBufferInfo(console, info);
|
||||
if( negative ) {
|
||||
if (negative) {
|
||||
info.wAttributes = invertAttributeColors(info.wAttributes);
|
||||
}
|
||||
}
|
||||
@ -109,14 +109,14 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
if (underline) {
|
||||
attributes |= BACKGROUND_INTENSITY;
|
||||
}
|
||||
if( negative ) {
|
||||
if (negative) {
|
||||
attributes = invertAttributeColors(attributes);
|
||||
}
|
||||
Kernel32.INSTANCE.SetConsoleTextAttribute(console, attributes);
|
||||
}
|
||||
|
||||
private short invertAttributeColors(short attributes) {
|
||||
// Swap the Foreground and Background bits.
|
||||
// Swap the the Foreground and Background bits.
|
||||
int fg = 0x000F & attributes;
|
||||
fg <<= 4;
|
||||
int bg = 0X00F0 & attributes;
|
||||
@ -183,26 +183,26 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
protected void processCursorUpLine(int count) throws IOException {
|
||||
getConsoleInfo();
|
||||
info.dwCursorPosition.X = 0;
|
||||
info.dwCursorPosition.Y -= (short)count;
|
||||
info.dwCursorPosition.Y -= (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
|
||||
protected void processCursorDownLine(int count) throws IOException {
|
||||
getConsoleInfo();
|
||||
info.dwCursorPosition.X = 0;
|
||||
info.dwCursorPosition.Y += (short)count;
|
||||
info.dwCursorPosition.Y += (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
|
||||
protected void processCursorLeft(int count) throws IOException {
|
||||
getConsoleInfo();
|
||||
info.dwCursorPosition.X -= (short)count;
|
||||
info.dwCursorPosition.X -= (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
|
||||
protected void processCursorRight(int count) throws IOException {
|
||||
getConsoleInfo();
|
||||
info.dwCursorPosition.X += (short)count;
|
||||
info.dwCursorPosition.X += (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
getConsoleInfo();
|
||||
int nb = Math.max(0, info.dwCursorPosition.Y + count - info.dwSize.Y + 1);
|
||||
if (nb != count) {
|
||||
info.dwCursorPosition.Y += (short)count;
|
||||
info.dwCursorPosition.Y += (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
if (nb > 0) {
|
||||
@ -226,7 +226,7 @@ public final class WindowsAnsiWriter extends AnsiWriter {
|
||||
|
||||
protected void processCursorUp(int count) throws IOException {
|
||||
getConsoleInfo();
|
||||
info.dwCursorPosition.Y -= (short)count;
|
||||
info.dwCursorPosition.Y -= (short) count;
|
||||
applyCursorPosition();
|
||||
}
|
||||
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
provides jdk.internal.org.jline.terminal.spi.JnaSupport with jdk.internal.org.jline.terminal.impl.jna.JnaSupportImpl;
|
@ -56,7 +56,7 @@ public class AbstractWindowsTerminalTest {
|
||||
return is.read();
|
||||
}
|
||||
};
|
||||
var t = new AbstractWindowsTerminal(out, "test", "vt100", null, -1, false, SignalHandler.SIG_DFL, isWrapper) {
|
||||
var t = new AbstractWindowsTerminal(out, "test", "vt100", null, false, SignalHandler.SIG_DFL, isWrapper) {
|
||||
@Override
|
||||
protected int getConsoleMode() {
|
||||
return -1;
|
||||
|
@ -59,7 +59,7 @@ public class KeyConversionTest {
|
||||
void checkKeyConversion(KeyEvent event, String expected) throws IOException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
new AbstractWindowsTerminal(new StringWriter(), "", "windows", Charset.forName("UTF-8"),
|
||||
0, true, SignalHandler.SIG_DFL, in -> in) {
|
||||
true, SignalHandler.SIG_DFL, in -> in) {
|
||||
@Override
|
||||
protected int getConsoleMode() {
|
||||
return 0;
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @summary Control Char <UNDEF> check for pty
|
||||
* @modules jdk.internal.le/jdk.internal.org.jline.terminal
|
||||
* jdk.internal.le/jdk.internal.org.jline.terminal.impl
|
||||
* jdk.internal.le/jdk.internal.org.jline.terminal.spi
|
||||
* @requires (os.family == "linux") | (os.family == "aix")
|
||||
*/
|
||||
|
||||
@ -35,10 +36,11 @@ import jdk.internal.org.jline.terminal.Attributes;
|
||||
import jdk.internal.org.jline.terminal.Attributes.ControlChar;
|
||||
import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
|
||||
import jdk.internal.org.jline.terminal.impl.ExecPty;
|
||||
import jdk.internal.org.jline.terminal.spi.TerminalProvider;
|
||||
|
||||
public class ExecPtyGetFlagsToSetTest extends ExecPty {
|
||||
public ExecPtyGetFlagsToSetTest(String name, boolean system) {
|
||||
super(name, system);
|
||||
public ExecPtyGetFlagsToSetTest(String name, TerminalProvider.Stream stream) {
|
||||
super(name, stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,7 +50,7 @@ public class ExecPtyGetFlagsToSetTest extends ExecPty {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ExecPtyGetFlagsToSetTest testPty =
|
||||
new ExecPtyGetFlagsToSetTest("stty", true);
|
||||
new ExecPtyGetFlagsToSetTest("stty", TerminalProvider.Stream.Output);
|
||||
|
||||
Attributes attr = new Attributes();
|
||||
Attributes current = new Attributes();
|
||||
|
Loading…
Reference in New Issue
Block a user