diff options
author | Paul Phillips <paulp@improving.org> | 2010-12-30 06:58:10 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-12-30 06:58:10 +0000 |
commit | 3e61c9a5aea00d3b7d7002713f6f9a0acc0a5b8e (patch) | |
tree | 14e4e4e422d5f84b8a7bdb111e7f5d83f78a3280 /src | |
parent | 3ec0583fb6724416d5ebda8a927bbdecc23ebef5 (diff) | |
download | scala-3e61c9a5aea00d3b7d7002713f6f9a0acc0a5b8e.tar.gz scala-3e61c9a5aea00d3b7d7002713f6f9a0acc0a5b8e.tar.bz2 scala-3e61c9a5aea00d3b7d7002713f6f9a0acc0a5b8e.zip |
More jline work from huynhjl.
repo and includes jline binary. No review.
Diffstat (limited to 'src')
5 files changed, 132 insertions, 62 deletions
diff --git a/src/jline/src/main/java/jline/AnsiWindowsTerminal.java b/src/jline/src/main/java/jline/AnsiWindowsTerminal.java index 43351952ff..aefbfff363 100644 --- a/src/jline/src/main/java/jline/AnsiWindowsTerminal.java +++ b/src/jline/src/main/java/jline/AnsiWindowsTerminal.java @@ -84,7 +84,7 @@ public class AnsiWindowsTerminal } @Override - public boolean newlineAtWrapNeeded() { + public boolean hasWeirdWrap() { return false; } } diff --git a/src/jline/src/main/java/jline/Terminal.java b/src/jline/src/main/java/jline/Terminal.java index fb86c07c12..a9ede87814 100644 --- a/src/jline/src/main/java/jline/Terminal.java +++ b/src/jline/src/main/java/jline/Terminal.java @@ -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(); diff --git a/src/jline/src/main/java/jline/TerminalSupport.java b/src/jline/src/main/java/jline/TerminalSupport.java index 22f51c5e80..9448b0d481 100644 --- a/src/jline/src/main/java/jline/TerminalSupport.java +++ b/src/jline/src/main/java/jline/TerminalSupport.java @@ -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; } diff --git a/src/jline/src/main/java/jline/console/ConsoleReader.java b/src/jline/src/main/java/jline/console/ConsoleReader.java index 44b0cbf866..b49966cf7e 100644 --- a/src/jline/src/main/java/jline/console/ConsoleReader.java +++ b/src/jline/src/main/java/jline/console/ConsoleReader.java @@ -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); - } + } else { + 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); + 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. } - } else { - back(chars.length); } -// 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? + } } diff --git a/src/jline/src/test/java/jline/example/Example.java b/src/jline/src/test/java/jline/example/Example.java index 0da3799cd3..84aee10af3 100644 --- a/src/jline/src/test/java/jline/example/Example.java +++ b/src/jline/src/test/java/jline/example/Example.java @@ -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); - - while ((line = reader.readLine("prompt> ")) != null) { - out.println("======>\"" + line + "\""); + PrintWriter out = new PrintWriter( + reader.getTerminal().wrapOutIfNeeded(System.out)); + + 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 |