More jline work from huynhjl. Updates source to current jline2

repo and includes jline binary.  No review.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23849 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2010-12-30 06:58:10 +00:00
parent f6e4e074c7
commit 67b6198449
6 changed files with 132 additions and 62 deletions

Binary file not shown.

View File

@ -84,7 +84,7 @@ public class AnsiWindowsTerminal
}
@Override
public boolean newlineAtWrapNeeded() {
public boolean hasWeirdWrap() {
return false;
}
}

View File

@ -40,9 +40,12 @@ public interface Terminal
OutputStream wrapOutIfNeeded(OutputStream out);
/**
* For terminals that don't wrap when character is written in last column.
* For terminals that don't wrap when character is written in last column,
* only when the next character is written.
* These are the ones that have 'am' and 'xn' termcap attributes (xterm and
* rxvt flavors falls under that category)
*/
boolean newlineAtWrapNeeded();
boolean hasWeirdWrap();
boolean isEchoEnabled();

View File

@ -111,7 +111,7 @@ public abstract class TerminalSupport
/**
* Defaults to true which was the behaviour before this method was added.
*/
public boolean newlineAtWrapNeeded() {
public boolean hasWeirdWrap() {
return true;
}

View File

@ -326,6 +326,8 @@ public class ConsoleReader
if (buf.length() != buf.cursor) { // not at end of line
back(buf.length() - buf.cursor - 1);
}
// force drawBuffer to check for weird wrap (after clear screen)
drawBuffer();
}
/**
@ -508,23 +510,6 @@ public class ConsoleReader
}
/* Handle case where terminal does not move cursor to the next line
* when a character is inserted at the width of the terminal. This also
* fixes backspace issue, where it assumes that the terminal is doing this.
*/
private final void newlineAtWrap() throws IOException {
/** On OSX this leads to failure to paste lines longer than the
* the terminal width. It spews some ansi control and truncates
* the paste.
*/
if (false && terminal.newlineAtWrapNeeded()) {
int width = getTerminal().getWidth();
if ((getCursorPosition() % width == 0) && getCurrentPosition() >= width)
println();
}
}
/**
* Write out the specified string to the buffer and the output stream.
*/
@ -532,7 +517,6 @@ public class ConsoleReader
buf.write(str);
print(str);
drawBuffer();
newlineAtWrap();
}
/**
@ -554,7 +538,6 @@ public class ConsoleReader
}
drawBuffer();
newlineAtWrap();
}
}
@ -567,25 +550,35 @@ public class ConsoleReader
private void drawBuffer(final int clear) throws IOException {
// debug ("drawBuffer: " + clear);
if (buf.cursor == buf.length() && clear == 0) {
return;
}
char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
if (mask != null) {
Arrays.fill(chars, mask);
}
print(chars);
clearAhead(clear);
if (terminal.isAnsiSupported()) {
if (chars.length > 0) {
// don't ask, it works
//back(Math.max(chars.length - 1, 1), true);
back(chars.length, true);
}
} else {
back(chars.length);
char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
if (mask != null) {
Arrays.fill(chars, mask);
}
print(chars);
clearAhead(clear, chars.length);
if (terminal.isAnsiSupported()) {
if (chars.length > 0) {
back(chars.length);
}
} else {
back(chars.length);
}
}
if (terminal.hasWeirdWrap()) {
int width = terminal.getWidth();
// best guess on whether the cursor is in that weird location...
// Need to do this without calling ansi cursor location methods
// otherwise it breaks paste of wrapped lines in xterm.
if (getCursorPosition() == width
&& buf.cursor == buf.length() && clear == 0) {
// the following workaround is reverse-engineered from looking
// at what bash sent to the terminal in the same situation
print(32); // move cursor to next line by printing dummy space
print(13); // CR / not newline.
}
}
// flush();
}
/**
@ -598,19 +591,35 @@ public class ConsoleReader
/**
* Clear ahead the specified number of characters without moving the cursor.
*
* @param num the number of characters to clear
* @param delta the difference between the internal cursor and the screen
* cursor - if > 0, assume some stuff was printed and weird wrap has to be
* checked
*/
private void clearAhead(final int num) throws IOException {
private void clearAhead(final int num, int delta) throws IOException {
if (num == 0) {
return;
}
if (terminal.isAnsiSupported()) {
printAnsiSequence("K");
// if cursor+num wraps, then we need to clear the line(s) below too
// it's possible the real cursor is in the last column of a terminal
// with weird wrapping.
int width = terminal.getWidth();
int cursor = getCursorPosition();
int curCol = cursor % width;
int endCol = (cursor + num) % width;
int screenCursorCol = getCursorPosition() + delta;
if (delta > 0 && terminal.hasWeirdWrap()
&& screenCursorCol % width == 0) {
// need to clear out the line below - cursor has not wrapped
printAnsiSequence("B");
printAnsiSequence("2K");
printAnsiSequence("A");
} else {
// clear current line
printAnsiSequence("K");
}
// if cursor+num wraps, then we need to clear the line(s) below too
int curCol = screenCursorCol % width;
int endCol = (screenCursorCol + num - 1) % width;
int lines = num / width;
if (endCol < curCol) lines++;
for (int i = 0; i < lines; i++) {
@ -631,29 +640,25 @@ public class ConsoleReader
// flush();
// reset the visual cursor
back(num, true);
back(num);
// flush();
}
private void back(final int num) throws IOException {
back(num, false);
}
/**
* Move the visual cursor backwards without modifying the buffer cursor.
* @param printed if true some characters were printed and we have to deal
* with new line at wrap
*/
private void back(final int num, boolean printed) throws IOException {
private void back(final int num) throws IOException {
if (num == 0) return;
if (terminal.isAnsiSupported()) {
int width = getTerminal().getWidth();
int cursor = getCursorPosition();
int realCursor = cursor + num;
// adjust cursor if it did not wrapped on its own
if (printed && terminal.newlineAtWrapNeeded() && realCursor%width == 0) {
realCursor--;
if (terminal.hasWeirdWrap() && realCursor%width == 0) {
if (getCurrentPosition() - 1 != realCursor%width) {
realCursor--;
}
}
int realCol = realCursor % width;
int newCol = cursor % width;
@ -702,6 +707,23 @@ public class ConsoleReader
if (terminal.isAnsiSupported()) {
// debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
printAnsiSequence("K");
// if cursor+num wraps, then we need to clear the line(s) below too
// last char printed is one pos less than cursor so we subtract
// one
/*
// TODO: fixme (does not work - test with reverse search with wrapping line and CTRL-E)
int endCol = (getCursorPosition() + num - 1) % termwidth;
int curCol = getCursorPosition() % termwidth;
if (endCol < curCol) lines++;
for (int i = 1; i < lines; i++) {
printAnsiSequence("B");
printAnsiSequence("2K");
}
for (int i = 1; i < lines; i++) {
printAnsiSequence("A");
}
return count;
*/
}
}
drawBuffer(count);
@ -819,6 +841,15 @@ public class ConsoleReader
int oldLine = (cursor - where) / width;
int newLine = cursor / width;
if (newLine > oldLine) {
if (terminal.hasWeirdWrap()) {
// scroll up if at bottom
// note:
// on rxvt cywgin terminal.getHeight() is incorrect
// MacOs xterm does not seem to support scrolling
if (getCurrentAnsiRow() == terminal.getHeight()) {
printAnsiSequence((newLine - oldLine) + "S");
}
}
printAnsiSequence((newLine - oldLine) + "B");
}
printAnsiSequence(1 +(cursor % width) + "G");
@ -1716,7 +1747,7 @@ public class ConsoleReader
}
int num = buf.buffer.length() - cp;
clearAhead(num);
clearAhead(num, 0);
for (int i = 0; i < num; i++) {
buf.buffer.deleteCharAt(len - i - 1);
@ -2104,4 +2135,30 @@ public class ConsoleReader
return -1; // TODO: throw exception instead?
}
// return row position, reported by the terminal
// needed to know whether to scroll up on cursor move in last col for weird
// wrapping terminals - not tested for anything else
private int getCurrentAnsiRow() {
// check for ByteArrayInputStream to disable for unit tests
if (terminal.isAnsiSupported() && !(in instanceof ByteArrayInputStream)) {
try {
printAnsiSequence("6n");
flush();
StringBuffer b = new StringBuffer(8);
// position is sent as <ESC>[{ROW};{COLUMN}R
int r;
while((r = in.read()) > -1 && r != 'R') {
if (r != 27 && r != '[') {
b.append((char) r);
}
}
String[] pos = b.toString().split(";");
return Integer.parseInt(pos[0]);
} catch (Exception x) {
// no luck
}
}
return -1; // TODO: throw exception instead?
}
}

View File

@ -22,8 +22,6 @@ public class Example
+ "\"foo\", \"bar\", and \"baz\"");
System.out
.println(" files - a completor that comples " + "file names");
System.out.println(" dictionary - a completor that comples "
+ "english dictionary words");
System.out.println(" classes - a completor that comples "
+ "java class names");
System.out
@ -31,6 +29,7 @@ public class Example
+ "the next line is a password");
System.out.println(" mask - is the character to print in place of "
+ "the actual password character");
System.out.println(" color - colored prompt and feedback");
System.out.println("\n E.g - java Example simple su '*'\n"
+ "will use the simple compleator with 'su' triggering\n"
+ "the use of '*' as a password mask.");
@ -39,10 +38,12 @@ public class Example
public static void main(String[] args) throws IOException {
Character mask = null;
String trigger = null;
boolean color = false;
ConsoleReader reader = new ConsoleReader();
reader.setBellEnabled(false);
reader.setPrompt("prompt> ");
if ((args == null) || (args.length == 0)) {
usage();
@ -61,6 +62,10 @@ public class Example
else if (args[0].equals("simple")) {
completors.add(new StringsCompleter("foo", "bar", "baz"));
}
else if (args[0].equals("color")) {
color = true;
reader.setPrompt("\u001B[1mfoo\u001B[0m@bar\u001B[32m@baz\u001B[0m> ");
}
else {
usage();
@ -78,10 +83,15 @@ public class Example
}
String line;
PrintWriter out = new PrintWriter(System.out);
PrintWriter out = new PrintWriter(
reader.getTerminal().wrapOutIfNeeded(System.out));
while ((line = reader.readLine("prompt> ")) != null) {
out.println("======>\"" + line + "\"");
while ((line = reader.readLine()) != null) {
if (color){
out.println("\u001B[33m======>\u001B[0m\"" + line + "\"");
} else {
out.println("======>\"" + line + "\"");
}
out.flush();
// If we input the special word then we will mask