changeset 57306:eeb1c0da2126

8229815: Upgrade Jline to 3.12.1 Reviewed-by: rfield
author jlahoda
date Mon, 04 Nov 2019 09:40:35 +0100
parents 197238c30630
children 1f7981ef8779
files src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/BindingReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/KeyMap.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Binding.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Buffer.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Completer.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletingParsedLine.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Expander.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Highlighter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/History.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Macro.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/MaskingCallback.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ParsedLine.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Reference.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/UserInterruptException.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Widget.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/BufferImpl.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultExpander.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/KillRing.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/SimpleMaskingCallback.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/UndoTree.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/AggregateCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/ArgumentCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/EnumCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/FileNameCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/NullCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/package-info.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/package-info.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/package-info.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Attributes.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Cursor.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/MouseEvent.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Size.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPosixTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPty.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsConsoleWriter.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/CursorSupport.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/DumbTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExecPty.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExternalTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/LineDisciplineTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/MouseSupport.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/NativeSignalHandler.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixPtyTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixSysTerminal.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/package-info.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/Pty.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ClosedException.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/DiffHelper.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ExecHelper.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InputStreamReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Levenshtein.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlocking.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStream.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStreamImpl.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReaderImpl.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ShutdownHooks.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Status.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WCWidth.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WriterOutputStream.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/capabilities.txt src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/colors.txt src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/dumb-colors.caps src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/package-info.java src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-conemu.caps src/jdk.internal.le/share/legal/jline.md src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinConsoleWriter.java src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Kernel32.java src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/WindowsAnsiWriter.java
diffstat 103 files changed, 1404 insertions(+), 644 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/BindingReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/BindingReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.keymap;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/KeyMap.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/KeyMap.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.keymap;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Binding.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Binding.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Buffer.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Buffer.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Completer.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Completer.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletingParsedLine.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletingParsedLine.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Expander.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Expander.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Highlighter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Highlighter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/History.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/History.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,11 +4,12 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
 import java.io.IOException;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Iterator;
 import java.util.ListIterator;
@@ -42,6 +43,26 @@
     void save() throws IOException;
 
     /**
+     * Write history to the file. If incremental only the events that are new since the last incremental operation to
+     * the file are added.
+     * @throws IOException if a problem occurs
+     */
+    void write(Path file, boolean incremental) throws IOException;
+
+    /**
+     * Append history to the file. If incremental only the events that are new since the last incremental operation to
+     * the file are added.
+     * @throws IOException if a problem occurs
+     */
+    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.
+     * @throws IOException if a problem occurs
+     */
+    void read(Path file, boolean incremental) throws IOException;
+
+    /**
      * Purge history.
      * @throws IOException if a problem occurs
      */
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
@@ -95,7 +95,10 @@
     String CALLBACK_FINISH = "callback-finish";
     String CALLBACK_KEYMAP = "callback-keymap";
 
+    String ACCEPT_AND_INFER_NEXT_HISTORY = "accept-and-infer-next-history";
+    String ACCEPT_AND_HOLD = "accept-and-hold";
     String ACCEPT_LINE = "accept-line";
+    String ACCEPT_LINE_AND_DOWN_HISTORY = "accept-line-and-down-history";
     String ARGUMENT_BASE = "argument-base";
     String BACKWARD_CHAR = "backward-char";
     String BACKWARD_DELETE_CHAR = "backward-delete-char";
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
@@ -85,7 +85,7 @@
     public LineReaderBuilder parser(Parser parser) {
         if (parser != null) {
             try {
-                if (!Boolean.parseBoolean(LineReader.PROP_SUPPORT_PARSEDLINE)
+                if (!Boolean.getBoolean(LineReader.PROP_SUPPORT_PARSEDLINE)
                         && !(parser.parse("", 0) instanceof CompletingParsedLine)) {
                     Log.warn("The Parser of class " + parser.getClass().getName() + " does not support the CompletingParsedLine interface. " +
                             "Completion with escaped or quoted words won't work correctly.");
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Macro.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Macro.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/MaskingCallback.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/MaskingCallback.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ParsedLine.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ParsedLine.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
@@ -16,6 +16,10 @@
         return parse(line, cursor, ParseContext.UNSPECIFIED);
     }
 
+    default boolean isEscapeChar(char ch) {
+        return ch == '\\';
+    }
+
     enum ParseContext {
         UNSPECIFIED,
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Reference.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Reference.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/UserInterruptException.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/UserInterruptException.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Widget.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Widget.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/BufferImpl.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/BufferImpl.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultExpander.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultExpander.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
@@ -18,6 +18,13 @@
 
 public class DefaultParser implements Parser {
 
+    public enum Bracket {
+        ROUND,   // ()
+        CURLY,   // {}
+        SQUARE,  // []
+        ANGLE;   // <>
+    }
+
     private char[] quoteChars = {'\'', '"'};
 
     private char[] escapeChars = {'\\'};
@@ -26,6 +33,10 @@
 
     private boolean eofOnEscapedNewLine;
 
+    private char[] openingBrackets = null;
+
+    private char[] closingBrackets = null;
+
     //
     // Chainable setters
     //
@@ -45,6 +56,11 @@
         return this;
     }
 
+    public DefaultParser eofOnUnclosedBracket(Bracket... brackets){
+        setEofOnUnclosedBracket(brackets);
+        return this;
+    }
+
     public DefaultParser eofOnEscapedNewLine(boolean eofOnEscapedNewLine) {
         this.eofOnEscapedNewLine = eofOnEscapedNewLine;
         return this;
@@ -86,6 +102,39 @@
         return eofOnEscapedNewLine;
     }
 
+    public void setEofOnUnclosedBracket(Bracket... brackets){
+        if (brackets == null) {
+            openingBrackets = null;
+            closingBrackets = null;
+        } else {
+            Set<Bracket> bs = new HashSet<>(Arrays.asList(brackets));
+            openingBrackets = new char[bs.size()];
+            closingBrackets = new char[bs.size()];
+            int i = 0;
+            for (Bracket b : bs) {
+                switch (b) {
+                case ROUND:
+                    openingBrackets[i] = '(';
+                    closingBrackets[i] = ')';
+                    break;
+                case CURLY:
+                    openingBrackets[i] = '{';
+                    closingBrackets[i] = '}';
+                    break;
+                case SQUARE:
+                    openingBrackets[i] = '[';
+                    closingBrackets[i] = ']';
+                    break;
+                case ANGLE:
+                    openingBrackets[i] = '<';
+                    closingBrackets[i] = '>';
+                    break;
+                }
+                i++;
+            }
+        }
+    }
+
     public ParsedLine parse(final String line, final int cursor, ParseContext context) {
         List<String> words = new LinkedList<>();
         StringBuilder current = new StringBuilder();
@@ -95,6 +144,8 @@
         int rawWordCursor = -1;
         int rawWordLength = -1;
         int rawWordStart = 0;
+        BracketChecker bracketChecker = new BracketChecker();
+        boolean quotedWord = false;
 
         for (int i = 0; (line != null) && (i < line.length()); i++) {
             // once we reach the cursor, set the
@@ -110,36 +161,35 @@
             if (quoteStart < 0 && isQuoteChar(line, i)) {
                 // Start a quote block
                 quoteStart = i;
-            } else if (quoteStart >= 0) {
-                // In a quote block
-                if (line.charAt(quoteStart) == line.charAt(i) && !isEscaped(line, i)) {
-                    // End the block; arg could be empty, but that's fine
+                if (current.length()==0) {
+                    quotedWord = true;
+                } else {
+                    current.append(line.charAt(i));
+                }
+            } else if (quoteStart >= 0 && line.charAt(quoteStart) == line.charAt(i) && !isEscaped(line, i)) {
+                // End quote block
+                if (!quotedWord) {
+                    current.append(line.charAt(i));
+                } else if (rawWordCursor >= 0 && rawWordLength < 0) {
+                    rawWordLength = i - rawWordStart + 1;
+                }
+                quoteStart = -1;
+                quotedWord = false;
+            } else if (quoteStart < 0 && isDelimiter(line, i)) {
+                // Delimiter
+                if (current.length() > 0) {
                     words.add(current.toString());
-                    current.setLength(0);
-                    quoteStart = -1;
+                    current.setLength(0); // reset the arg
                     if (rawWordCursor >= 0 && rawWordLength < 0) {
-                        rawWordLength = i - rawWordStart + 1;
-                    }
-                } else {
-                    if (!isEscapeChar(line, i)) {
-                        // Take the next character
-                        current.append(line.charAt(i));
+                        rawWordLength = i - rawWordStart;
                     }
                 }
+                rawWordStart = i + 1;
             } else {
-                // Not in a quote block
-                if (isDelimiter(line, i)) {
-                    if (current.length() > 0) {
-                        words.add(current.toString());
-                        current.setLength(0); // reset the arg
-                        if (rawWordCursor >= 0 && rawWordLength < 0) {
-                            rawWordLength = i - rawWordStart;
-                        }
-                    }
-                    rawWordStart = i + 1;
-                } else {
-                    if (!isEscapeChar(line, i)) {
-                        current.append(line.charAt(i));
+                if (!isEscapeChar(line, i)) {
+                    current.append(line.charAt(i));
+                    if (quoteStart < 0) {
+                        bracketChecker.check(line, i);
                     }
                 }
             }
@@ -159,21 +209,29 @@
             rawWordLength = rawWordCursor;
         }
 
-        if (eofOnEscapedNewLine && isEscapeChar(line, line.length() - 1)) {
-            throw new EOFError(-1, -1, "Escaped new line", "newline");
-        }
-        if (eofOnUnclosedQuote && quoteStart >= 0 && context != ParseContext.COMPLETE) {
-            throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
-                    ? "quote" : "dquote");
+        if (context != ParseContext.COMPLETE) {
+            if (eofOnEscapedNewLine && isEscapeChar(line, line.length() - 1)) {
+                throw new EOFError(-1, -1, "Escaped new line", "newline");
+            }
+            if (eofOnUnclosedQuote && quoteStart >= 0) {
+                throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
+                        ? "quote" : "dquote");
+            }
+            if (bracketChecker.isOpeningBracketMissing()) {
+                throw new EOFError(-1, -1, "Missing opening bracket", "missing: " + bracketChecker.getMissingOpeningBracket());
+            }
+            if (bracketChecker.isClosingBracketMissing()) {
+                throw new EOFError(-1, -1, "Missing closing brackets", "add: " + bracketChecker.getMissingClosingBrackets());
+            }
         }
 
-        String openingQuote = quoteStart >= 0 ? line.substring(quoteStart, quoteStart + 1) : null;
+        String openingQuote = quotedWord ? line.substring(quoteStart, quoteStart + 1) : null;
         return new ArgumentList(line, words, wordIndex, wordCursor, cursor, openingQuote, rawWordCursor, rawWordLength);
     }
 
     /**
      * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
-     * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
+     * escaped by any of {@link #getQuoteChars}, and is not escaped by any of the {@link #getEscapeChars}, and
      * returns true from {@link #isDelimiterChar}.
      *
      * @param buffer    The complete command buffer
@@ -202,6 +260,18 @@
         return false;
     }
 
+    @Override
+    public boolean isEscapeChar(char ch) {
+        if (escapeChars != null) {
+            for (char e : escapeChars) {
+                if (e == ch) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Check if this character is a valid escape char (i.e. one that has not been escaped)
      *
@@ -216,14 +286,8 @@
         if (pos < 0) {
             return false;
         }
-        if (escapeChars != null) {
-            for (char e : escapeChars) {
-                if (e == buffer.charAt(pos)) {
-                    return !isEscaped(buffer, pos);
-                }
-            }
-        }
-        return false;
+        char ch = buffer.charAt(pos);
+        return isEscapeChar(ch) && !isEscaped(buffer, pos);
     }
 
     /**
@@ -245,7 +309,7 @@
 
     /**
      * Returns true if the character at the specified position if a delimiter. This method will only be called if
-     * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
+     * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by any of the
      * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
      *
      * @param buffer
@@ -280,6 +344,67 @@
         return false;
     }
 
+    private class BracketChecker {
+        private int missingOpeningBracket = -1;
+        private List<Integer> nested = new ArrayList<>();
+
+        public BracketChecker(){}
+
+        public void check(final CharSequence buffer, final int pos){
+            if (openingBrackets == null || pos < 0) {
+                return;
+            }
+            int bid = bracketId(openingBrackets, buffer, pos);
+            if (bid >= 0) {
+                nested.add(bid);
+            } else {
+                bid = bracketId(closingBrackets, buffer, pos);
+                if (bid >= 0) {
+                    if (!nested.isEmpty() && bid == nested.get(nested.size()-1)) {
+                        nested.remove(nested.size()-1);
+                    } else {
+                        missingOpeningBracket = bid;
+                    }
+                }
+            }
+        }
+
+        public boolean isOpeningBracketMissing(){
+            return missingOpeningBracket != -1;
+        }
+
+        public String getMissingOpeningBracket(){
+            if (!isOpeningBracketMissing()) {
+                return null;
+            }
+            return Character.toString(openingBrackets[missingOpeningBracket]);
+        }
+
+        public boolean isClosingBracketMissing(){
+            return !nested.isEmpty();
+        }
+
+        public String getMissingClosingBrackets(){
+            if (!isClosingBracketMissing()) {
+                return null;
+            }
+            StringBuilder out = new StringBuilder();
+            for (int i = nested.size() - 1; i > -1; i--) {
+                out.append(closingBrackets[nested.get(i)]);
+            }
+            return out.toString();
+        }
+
+        private int bracketId(final char[] brackets, final CharSequence buffer, final int pos){
+            for (int i=0; i < brackets.length; i++) {
+                if (buffer.charAt(pos) == brackets[i]) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+    }
+
     /**
      * The result of a delimited buffer.
      *
@@ -367,26 +492,50 @@
         public CharSequence escape(CharSequence candidate, boolean complete) {
             StringBuilder sb = new StringBuilder(candidate);
             Predicate<Integer> needToBeEscaped;
-            // Completion is protected by an opening quote:
-            // Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
-            // Also, close the quote at the end
-            if (openingQuote != null) {
-                needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote);
-            }
-            // No quote protection, need to escape everything: delimiter chars (spaces), quote chars
-            // and escapes themselves
-            else {
-                needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i));
-            }
-            for (int i = 0; i < sb.length(); i++) {
-                if (needToBeEscaped.test(i)) {
-                    sb.insert(i++, escapeChars[0]);
+            String quote = openingQuote;
+            boolean middleQuotes = false;
+            if (openingQuote==null) {
+                for (int i=0; i < sb.length(); i++) {
+                    if (isQuoteChar(sb, i)) {
+                        middleQuotes = true;
+                        break;
+                    }
                 }
             }
-            if (openingQuote != null) {
-                sb.insert(0, openingQuote);
+            if (escapeChars != null) {
+                // Completion is protected by an opening quote:
+                // Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
+                // Also, close the quote at the end
+                if (openingQuote != null) {
+                    needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote);
+                }
+                // Completion is protected by middle quotes:
+                // Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does.
+                else if (middleQuotes) {
+                    needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i));
+                }
+                // No quote protection, need to escape everything: delimiter chars (spaces), quote chars
+                // and escapes themselves
+                else {
+                    needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i));
+                }
+                for (int i = 0; i < sb.length(); i++) {
+                    if (needToBeEscaped.test(i)) {
+                        sb.insert(i++, escapeChars[0]);
+                    }
+                }
+            } else if (openingQuote == null && !middleQuotes) {
+                for (int i = 0; i < sb.length(); i++) {
+                    if (isDelimiterChar(sb, i)) {
+                        quote = "'";
+                        break;
+                    }
+                }
+            }
+            if (quote != null) {
+                sb.insert(0, quote);
                 if (complete) {
-                    sb.append(openingQuote);
+                    sb.append(quote);
                 }
             }
             return sb;
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/KillRing.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/KillRing.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2018, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
@@ -17,10 +17,13 @@
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
 import jdk.internal.org.jline.keymap.BindingReader;
@@ -32,6 +35,7 @@
 import jdk.internal.org.jline.terminal.Attributes.ControlChar;
 import jdk.internal.org.jline.terminal.Terminal.Signal;
 import jdk.internal.org.jline.terminal.Terminal.SignalHandler;
+import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
 import jdk.internal.org.jline.utils.AttributedString;
 import jdk.internal.org.jline.utils.AttributedStringBuilder;
 import jdk.internal.org.jline.utils.AttributedStyle;
@@ -159,8 +163,8 @@
 
     protected final Size size = new Size();
 
-    protected AttributedString prompt;
-    protected AttributedString rightPrompt;
+    protected AttributedString prompt = AttributedString.EMPTY;
+    protected AttributedString rightPrompt = AttributedString.EMPTY;
 
     protected MaskingCallback maskingCallback;
 
@@ -210,6 +214,10 @@
     protected UndoTree<Buffer> undo = new UndoTree<>(this::setBuffer);
     protected boolean isUndo;
 
+    /**
+     * State lock
+     */
+    protected final ReentrantLock lock = new ReentrantLock();
     /*
      * Current internal state of the line reader
      */
@@ -239,6 +247,11 @@
 
     protected int smallTerminalOffset = 0;
 
+    /*
+     * accept-and-infer-next-history, accept-and-hold & accept-line-and-down-history
+     */
+    protected boolean nextCommandFromHistory = false;
+    protected int nextHistoryId = -1;
 
 
     public LineReaderImpl(Terminal terminal) throws IOException {
@@ -266,6 +279,7 @@
         builtinWidgets = builtinWidgets();
         widgets = new HashMap<>(builtinWidgets);
         bindingReader = new BindingReader(terminal.reader());
+        doDisplay();
     }
 
     public Terminal getTerminal() {
@@ -467,8 +481,7 @@
         SignalHandler previousWinchHandler = null;
         SignalHandler previousContHandler = null;
         Attributes originalAttributes = null;
-        boolean dumb = Terminal.TYPE_DUMB.equals(terminal.getType())
-                    || Terminal.TYPE_DUMB_COLOR.equals(terminal.getType());
+        boolean dumb = isTerminalDumb();
         try {
 
             this.maskingCallback = maskingCallback;
@@ -495,6 +508,17 @@
             if (buffer != null) {
                 buf.write(buffer);
             }
+            if (nextCommandFromHistory && nextHistoryId > 0) {
+                if (history.size() > nextHistoryId) {
+                    history.moveTo(nextHistoryId);
+                } else {
+                    history.moveTo(history.last());
+                }
+                buf.write(history.current());
+            } else {
+                nextHistoryId = -1;
+            }
+            nextCommandFromHistory = false;
             undo.clear();
             parsedLine = null;
             keyMap = MAIN;
@@ -503,7 +527,9 @@
                 history.attach(this);
             }
 
-            synchronized (this) {
+            try {
+                lock.lock();
+
                 this.reading = true;
 
                 previousIntrHandler = terminal.handle(Signal.INT, signal -> readLineThread.interrupt());
@@ -511,18 +537,7 @@
                 previousContHandler = terminal.handle(Signal.CONT, this::handleSignal);
                 originalAttributes = terminal.enterRawMode();
 
-                // Cache terminal size for the duration of the call to readLine()
-                // It will eventually be updated with WINCH signals
-                size.copy(terminal.getSize());
-
-                display = new Display(terminal, false);
-                if (size.getRows() == 0 || size.getColumns() == 0) {
-                    display.resize(1, Integer.MAX_VALUE);
-                } else {
-                    display.resize(size.getRows(), size.getColumns());
-                }
-                if (isSet(Option.DELAY_LINE_WRAP))
-                    display.setDelayLineWrap(true);
+                doDisplay();
 
                 // Move into application mode
                 if (!dumb) {
@@ -547,6 +562,8 @@
                 // Draw initial prompt
                 redrawLine();
                 redisplay();
+            } finally {
+                lock.unlock();
             }
 
             while (true) {
@@ -578,7 +595,8 @@
                     regionActive = RegionType.NONE;
                 }
 
-                synchronized (this) {
+                try {
+                    lock.lock();
                     // Get executable widget
                     Buffer copy = buf.copy();
                     Widget w = getWidget(o);
@@ -610,6 +628,8 @@
                     if (!dumb) {
                         redisplay();
                     }
+                } finally {
+                    lock.unlock();
                 }
             }
         } catch (IOError e) {
@@ -620,7 +640,9 @@
             }
         }
         finally {
-            synchronized (this) {
+            try {
+                lock.lock();
+
                 this.reading = false;
 
                 cleanup();
@@ -636,26 +658,54 @@
                 if (previousContHandler != null) {
                     terminal.handle(Signal.CONT, previousContHandler);
                 }
+            } finally {
+                lock.unlock();
             }
             startedReading.set(false);
         }
     }
 
+    private boolean isTerminalDumb(){
+        return Terminal.TYPE_DUMB.equals(terminal.getType())
+                || Terminal.TYPE_DUMB_COLOR.equals(terminal.getType());
+    }
+
+    private void doDisplay(){
+        // Cache terminal size for the duration of the call to readLine()
+        // It will eventually be updated with WINCH signals
+        size.copy(terminal.getBufferSize());
+
+        display = new Display(terminal, false);
+        if (size.getRows() == 0 || size.getColumns() == 0) {
+            display.resize(1, Integer.MAX_VALUE);
+        } else {
+            display.resize(size.getRows(), size.getColumns());
+        }
+        if (isSet(Option.DELAY_LINE_WRAP))
+            display.setDelayLineWrap(true);
+    }
+
     @Override
-    public synchronized void printAbove(String str) {
-        boolean reading = this.reading;
-        if (reading) {
-            display.update(Collections.emptyList(), 0);
-        }
-        if (str.endsWith("\n")) {
-            terminal.writer().print(str);
-        } else {
-            terminal.writer().println(str);
-        }
-        if (reading) {
-            redisplay(false);
-        }
-        terminal.flush();
+    public void printAbove(String str) {
+        try {
+            lock.lock();
+
+            boolean reading = this.reading;
+            if (reading) {
+                display.update(Collections.emptyList(), 0);
+            }
+            if (str.endsWith("\n") || str.endsWith("\n\033[m") || str.endsWith("\n\033[0m")) {
+                terminal.writer().print(str);
+            } else {
+                terminal.writer().println(str);
+            }
+            if (reading) {
+                redisplay(false);
+            }
+            terminal.flush();
+        } finally {
+            lock.unlock();
+        }
     }
 
     @Override
@@ -664,8 +714,13 @@
     }
 
     @Override
-    public synchronized boolean isReading() {
-        return reading;
+    public boolean isReading() {
+        try {
+            lock.lock();
+            return reading;
+        } finally {
+            lock.unlock();
+        }
     }
 
     /* Make sure we position the cursor on column 0 */
@@ -700,27 +755,32 @@
             sb.append(" ");
             sb.append(KeyMap.key(terminal, Capability.carriage_return));
         }
-        print(sb.toAnsi(terminal));
+        sb.print(terminal);
         return true;
     }
 
     @Override
-    public synchronized void callWidget(String name) {
-        if (!reading) {
-            throw new IllegalStateException("Widgets can only be called during a `readLine` call");
-        }
+    public void callWidget(String name) {
         try {
-            Widget w;
-            if (name.startsWith(".")) {
-                w = builtinWidgets.get(name.substring(1));
-            } else {
-                w = widgets.get(name);
-            }
-            if (w != null) {
-                w.apply();
-            }
-        } catch (Throwable t) {
-            Log.debug("Error executing widget '", name, "'", t);
+            lock.lock();
+            if (!reading) {
+                throw new IllegalStateException("Widgets can only be called during a `readLine` call");
+            }
+            try {
+                Widget w;
+                if (name.startsWith(".")) {
+                    w = builtinWidgets.get(name.substring(1));
+                } else {
+                    w = widgets.get(name);
+                }
+                if (w != null) {
+                    w.apply();
+                }
+            } catch (Throwable t) {
+                Log.debug("Error executing widget '", name, "'", t);
+            }
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -760,13 +820,35 @@
      * @return the character, or -1 if an EOF is received.
      */
     public int readCharacter() {
-        return bindingReader.readCharacter();
+        if (lock.isHeldByCurrentThread()) {
+            try {
+                lock.unlock();
+                return bindingReader.readCharacter();
+            } finally {
+                lock.lock();
+            }
+        } else {
+            return bindingReader.readCharacter();
+        }
     }
 
     public int peekCharacter(long timeout) {
         return bindingReader.peekCharacter(timeout);
     }
 
+    protected <T> T doReadBinding(KeyMap<T> keys, KeyMap<T> local) {
+        if (lock.isHeldByCurrentThread()) {
+            try {
+                lock.unlock();
+                return bindingReader.readBinding(keys, local);
+            } finally {
+                lock.lock();
+            }
+        } else {
+            return bindingReader.readBinding(keys, local);
+        }
+    }
+
     /**
      * Read from the input stream and decode an operation from the key map.
      *
@@ -783,7 +865,7 @@
     }
 
     public Binding readBinding(KeyMap<Binding> keys, KeyMap<Binding> local) {
-        Binding o = bindingReader.readBinding(keys, local);
+        Binding o = doReadBinding(keys, local);
         /*
          * The kill ring keeps record of whether or not the
          * previous command was a yank or a kill. We reset
@@ -926,7 +1008,7 @@
                     if (ch != '\n') {
                         sb.append(ch);
                     }
-                } else if (ch == '\\') {
+                } else if (parser.isEscapeChar(ch)) {
                     escaped = true;
                 } else {
                     sb.append(ch);
@@ -948,13 +1030,18 @@
 
     protected void handleSignal(Signal signal) {
         if (signal == Signal.WINCH) {
-            size.copy(terminal.getSize());
+            Status status = Status.getStatus(terminal, false);
+            if (status != null) {
+                status.hardReset();
+            }
+            size.copy(terminal.getBufferSize());
             display.resize(size.getRows(), size.getColumns());
+            redrawLine();
             redisplay();
         }
         else if (signal == Signal.CONT) {
             terminal.enterRawMode();
-            size.copy(terminal.getSize());
+            size.copy(terminal.getBufferSize());
             display.resize(size.getRows(), size.getColumns());
             terminal.puts(Capability.keypad_xmit);
             redrawLine();
@@ -1903,7 +1990,7 @@
         while (true) {
             post = () -> new AttributedString(searchPrompt + searchBuffer.toString() + "_");
             redisplay();
-            Binding b = bindingReader.readBinding(keyMap);
+            Binding b = doReadBinding(keyMap, null);
             if (b instanceof Reference) {
                 String func = ((Reference) b).name();
                 switch (func) {
@@ -2300,7 +2387,7 @@
         } else {
             viMoveMode = mode;
             mark = -1;
-            Binding b = bindingReader.readBinding(getKeys(), keyMaps.get(VIOPP));
+            Binding b = doReadBinding(getKeys(), keyMaps.get(VIOPP));
             if (b == null || new Reference(SEND_BREAK).equals(b)) {
                 viMoveMode = ViMoveMode.NORMAL;
                 mark = oldMark;
@@ -2710,6 +2797,42 @@
         return acceptLine();
     }
 
+    protected boolean acceptAndHold() {
+        nextCommandFromHistory = false;
+        acceptLine();
+        if (!buf.toString().isEmpty()) {
+            nextHistoryId = Integer.MAX_VALUE;
+            nextCommandFromHistory = true;
+        }
+        return nextCommandFromHistory;
+    }
+
+    protected boolean acceptLineAndDownHistory() {
+        nextCommandFromHistory = false;
+        acceptLine();
+        if (nextHistoryId < 0) {
+            nextHistoryId = history.index();
+        }
+        if (history.size() > nextHistoryId + 1) {
+            nextHistoryId++;
+            nextCommandFromHistory = true;
+        }
+        return nextCommandFromHistory;
+    }
+
+    protected boolean acceptAndInferNextHistory() {
+        nextCommandFromHistory = false;
+        acceptLine();
+        if (!buf.toString().isEmpty()) {
+            nextHistoryId = searchBackwards(buf.toString(), history.last());
+            if (nextHistoryId >= 0 && history.size() > nextHistoryId + 1) {
+                nextHistoryId++;
+                nextCommandFromHistory = true;
+            }
+        }
+        return nextCommandFromHistory;
+    }
+
     protected boolean acceptLine() {
         parsedLine = null;
         if (!isSet(Option.DISABLE_EVENT_EXPANSION)) {
@@ -3343,255 +3466,317 @@
 
     protected Map<String, Widget> builtinWidgets() {
         Map<String, Widget> widgets = new HashMap<>();
-        widgets.put(ACCEPT_LINE, this::acceptLine);
-        widgets.put(ARGUMENT_BASE, this::argumentBase);
-        widgets.put(BACKWARD_CHAR, this::backwardChar);
-        widgets.put(BACKWARD_DELETE_CHAR, this::backwardDeleteChar);
-        widgets.put(BACKWARD_DELETE_WORD, this::backwardDeleteWord);
-        widgets.put(BACKWARD_KILL_LINE, this::backwardKillLine);
-        widgets.put(BACKWARD_KILL_WORD, this::backwardKillWord);
-        widgets.put(BACKWARD_WORD, this::backwardWord);
-        widgets.put(BEEP, this::beep);
-        widgets.put(BEGINNING_OF_BUFFER_OR_HISTORY, this::beginningOfBufferOrHistory);
-        widgets.put(BEGINNING_OF_HISTORY, this::beginningOfHistory);
-        widgets.put(BEGINNING_OF_LINE, this::beginningOfLine);
-        widgets.put(BEGINNING_OF_LINE_HIST, this::beginningOfLineHist);
-        widgets.put(CAPITALIZE_WORD, this::capitalizeWord);
-        widgets.put(CLEAR, this::clear);
-        widgets.put(CLEAR_SCREEN, this::clearScreen);
-        widgets.put(COMPLETE_PREFIX, this::completePrefix);
-        widgets.put(COMPLETE_WORD, this::completeWord);
-        widgets.put(COPY_PREV_WORD, this::copyPrevWord);
-        widgets.put(COPY_REGION_AS_KILL, this::copyRegionAsKill);
-        widgets.put(DELETE_CHAR, this::deleteChar);
-        widgets.put(DELETE_CHAR_OR_LIST, this::deleteCharOrList);
-        widgets.put(DELETE_WORD, this::deleteWord);
-        widgets.put(DIGIT_ARGUMENT, this::digitArgument);
-        widgets.put(DO_LOWERCASE_VERSION, this::doLowercaseVersion);
-        widgets.put(DOWN_CASE_WORD, this::downCaseWord);
-        widgets.put(DOWN_LINE, this::downLine);
-        widgets.put(DOWN_LINE_OR_HISTORY, this::downLineOrHistory);
-        widgets.put(DOWN_LINE_OR_SEARCH, this::downLineOrSearch);
-        widgets.put(DOWN_HISTORY, this::downHistory);
-        widgets.put(EMACS_EDITING_MODE, this::emacsEditingMode);
-        widgets.put(EMACS_BACKWARD_WORD, this::emacsBackwardWord);
-        widgets.put(EMACS_FORWARD_WORD, this::emacsForwardWord);
-        widgets.put(END_OF_BUFFER_OR_HISTORY, this::endOfBufferOrHistory);
-        widgets.put(END_OF_HISTORY, this::endOfHistory);
-        widgets.put(END_OF_LINE, this::endOfLine);
-        widgets.put(END_OF_LINE_HIST, this::endOfLineHist);
-        widgets.put(EXCHANGE_POINT_AND_MARK, this::exchangePointAndMark);
-        widgets.put(EXPAND_HISTORY, this::expandHistory);
-        widgets.put(EXPAND_OR_COMPLETE, this::expandOrComplete);
-        widgets.put(EXPAND_OR_COMPLETE_PREFIX, this::expandOrCompletePrefix);
-        widgets.put(EXPAND_WORD, this::expandWord);
-        widgets.put(FRESH_LINE, this::freshLine);
-        widgets.put(FORWARD_CHAR, this::forwardChar);
-        widgets.put(FORWARD_WORD, this::forwardWord);
-        widgets.put(HISTORY_INCREMENTAL_SEARCH_BACKWARD, this::historyIncrementalSearchBackward);
-        widgets.put(HISTORY_INCREMENTAL_SEARCH_FORWARD, this::historyIncrementalSearchForward);
-        widgets.put(HISTORY_SEARCH_BACKWARD, this::historySearchBackward);
-        widgets.put(HISTORY_SEARCH_FORWARD, this::historySearchForward);
-        widgets.put(INSERT_CLOSE_CURLY, this::insertCloseCurly);
-        widgets.put(INSERT_CLOSE_PAREN, this::insertCloseParen);
-        widgets.put(INSERT_CLOSE_SQUARE, this::insertCloseSquare);
-        widgets.put(INSERT_COMMENT, this::insertComment);
-        widgets.put(KILL_BUFFER, this::killBuffer);
-        widgets.put(KILL_LINE, this::killLine);
-        widgets.put(KILL_REGION, this::killRegion);
-        widgets.put(KILL_WHOLE_LINE, this::killWholeLine);
-        widgets.put(KILL_WORD, this::killWord);
-        widgets.put(LIST_CHOICES, this::listChoices);
-        widgets.put(MENU_COMPLETE, this::menuComplete);
-        widgets.put(MENU_EXPAND_OR_COMPLETE, this::menuExpandOrComplete);
-        widgets.put(NEG_ARGUMENT, this::negArgument);
-        widgets.put(OVERWRITE_MODE, this::overwriteMode);
-//        widgets.put(QUIT, this::quit);
-        widgets.put(QUOTED_INSERT, this::quotedInsert);
-        widgets.put(REDISPLAY, this::redisplay);
-        widgets.put(REDRAW_LINE, this::redrawLine);
-        widgets.put(REDO, this::redo);
-        widgets.put(SELF_INSERT, this::selfInsert);
-        widgets.put(SELF_INSERT_UNMETA, this::selfInsertUnmeta);
-        widgets.put(SEND_BREAK, this::sendBreak);
-        widgets.put(SET_MARK_COMMAND, this::setMarkCommand);
-        widgets.put(TRANSPOSE_CHARS, this::transposeChars);
-        widgets.put(TRANSPOSE_WORDS, this::transposeWords);
-        widgets.put(UNDEFINED_KEY, this::undefinedKey);
-        widgets.put(UNIVERSAL_ARGUMENT, this::universalArgument);
-        widgets.put(UNDO, this::undo);
-        widgets.put(UP_CASE_WORD, this::upCaseWord);
-        widgets.put(UP_HISTORY, this::upHistory);
-        widgets.put(UP_LINE, this::upLine);
-        widgets.put(UP_LINE_OR_HISTORY, this::upLineOrHistory);
-        widgets.put(UP_LINE_OR_SEARCH, this::upLineOrSearch);
-        widgets.put(VI_ADD_EOL, this::viAddEol);
-        widgets.put(VI_ADD_NEXT, this::viAddNext);
-        widgets.put(VI_BACKWARD_CHAR, this::viBackwardChar);
-        widgets.put(VI_BACKWARD_DELETE_CHAR, this::viBackwardDeleteChar);
-        widgets.put(VI_BACKWARD_BLANK_WORD, this::viBackwardBlankWord);
-        widgets.put(VI_BACKWARD_BLANK_WORD_END, this::viBackwardBlankWordEnd);
-        widgets.put(VI_BACKWARD_KILL_WORD, this::viBackwardKillWord);
-        widgets.put(VI_BACKWARD_WORD, this::viBackwardWord);
-        widgets.put(VI_BACKWARD_WORD_END, this::viBackwardWordEnd);
-        widgets.put(VI_BEGINNING_OF_LINE, this::viBeginningOfLine);
-        widgets.put(VI_CMD_MODE, this::viCmdMode);
-        widgets.put(VI_DIGIT_OR_BEGINNING_OF_LINE, this::viDigitOrBeginningOfLine);
-        widgets.put(VI_DOWN_LINE_OR_HISTORY, this::viDownLineOrHistory);
-        widgets.put(VI_CHANGE, this::viChange);
-        widgets.put(VI_CHANGE_EOL, this::viChangeEol);
-        widgets.put(VI_CHANGE_WHOLE_LINE, this::viChangeWholeLine);
-        widgets.put(VI_DELETE_CHAR, this::viDeleteChar);
-        widgets.put(VI_DELETE, this::viDelete);
-        widgets.put(VI_END_OF_LINE, this::viEndOfLine);
-        widgets.put(VI_KILL_EOL, this::viKillEol);
-        widgets.put(VI_FIRST_NON_BLANK, this::viFirstNonBlank);
-        widgets.put(VI_FIND_NEXT_CHAR, this::viFindNextChar);
-        widgets.put(VI_FIND_NEXT_CHAR_SKIP, this::viFindNextCharSkip);
-        widgets.put(VI_FIND_PREV_CHAR, this::viFindPrevChar);
-        widgets.put(VI_FIND_PREV_CHAR_SKIP, this::viFindPrevCharSkip);
-        widgets.put(VI_FORWARD_BLANK_WORD, this::viForwardBlankWord);
-        widgets.put(VI_FORWARD_BLANK_WORD_END, this::viForwardBlankWordEnd);
-        widgets.put(VI_FORWARD_CHAR, this::viForwardChar);
-        widgets.put(VI_FORWARD_WORD, this::viForwardWord);
-        widgets.put(VI_FORWARD_WORD, this::viForwardWord);
-        widgets.put(VI_FORWARD_WORD_END, this::viForwardWordEnd);
-        widgets.put(VI_HISTORY_SEARCH_BACKWARD, this::viHistorySearchBackward);
-        widgets.put(VI_HISTORY_SEARCH_FORWARD, this::viHistorySearchForward);
-        widgets.put(VI_INSERT, this::viInsert);
-        widgets.put(VI_INSERT_BOL, this::viInsertBol);
-        widgets.put(VI_INSERT_COMMENT, this::viInsertComment);
-        widgets.put(VI_JOIN, this::viJoin);
-        widgets.put(VI_KILL_LINE, this::viKillWholeLine);
-        widgets.put(VI_MATCH_BRACKET, this::viMatchBracket);
-        widgets.put(VI_OPEN_LINE_ABOVE, this::viOpenLineAbove);
-        widgets.put(VI_OPEN_LINE_BELOW, this::viOpenLineBelow);
-        widgets.put(VI_PUT_AFTER, this::viPutAfter);
-        widgets.put(VI_PUT_BEFORE, this::viPutBefore);
-        widgets.put(VI_REPEAT_FIND, this::viRepeatFind);
-        widgets.put(VI_REPEAT_SEARCH, this::viRepeatSearch);
-        widgets.put(VI_REPLACE_CHARS, this::viReplaceChars);
-        widgets.put(VI_REV_REPEAT_FIND, this::viRevRepeatFind);
-        widgets.put(VI_REV_REPEAT_SEARCH, this::viRevRepeatSearch);
-        widgets.put(VI_SWAP_CASE, this::viSwapCase);
-        widgets.put(VI_UP_LINE_OR_HISTORY, this::viUpLineOrHistory);
-        widgets.put(VI_YANK, this::viYankTo);
-        widgets.put(VI_YANK_WHOLE_LINE, this::viYankWholeLine);
-        widgets.put(VISUAL_LINE_MODE, this::visualLineMode);
-        widgets.put(VISUAL_MODE, this::visualMode);
-        widgets.put(WHAT_CURSOR_POSITION, this::whatCursorPosition);
-        widgets.put(YANK, this::yank);
-        widgets.put(YANK_POP, this::yankPop);
-        widgets.put(MOUSE, this::mouse);
-        widgets.put(BEGIN_PASTE, this::beginPaste);
-        widgets.put(FOCUS_IN, this::focusIn);
-        widgets.put(FOCUS_OUT, this::focusOut);
+        addBuiltinWidget(widgets, ACCEPT_AND_INFER_NEXT_HISTORY, this::acceptAndInferNextHistory);
+        addBuiltinWidget(widgets, ACCEPT_AND_HOLD, this::acceptAndHold);
+        addBuiltinWidget(widgets, ACCEPT_LINE, this::acceptLine);
+        addBuiltinWidget(widgets, ACCEPT_LINE_AND_DOWN_HISTORY, this::acceptLineAndDownHistory);
+        addBuiltinWidget(widgets, ARGUMENT_BASE, this::argumentBase);
+        addBuiltinWidget(widgets, BACKWARD_CHAR, this::backwardChar);
+        addBuiltinWidget(widgets, BACKWARD_DELETE_CHAR, this::backwardDeleteChar);
+        addBuiltinWidget(widgets, BACKWARD_DELETE_WORD, this::backwardDeleteWord);
+        addBuiltinWidget(widgets, BACKWARD_KILL_LINE, this::backwardKillLine);
+        addBuiltinWidget(widgets, BACKWARD_KILL_WORD, this::backwardKillWord);
+        addBuiltinWidget(widgets, BACKWARD_WORD, this::backwardWord);
+        addBuiltinWidget(widgets, BEEP, this::beep);
+        addBuiltinWidget(widgets, BEGINNING_OF_BUFFER_OR_HISTORY, this::beginningOfBufferOrHistory);
+        addBuiltinWidget(widgets, BEGINNING_OF_HISTORY, this::beginningOfHistory);
+        addBuiltinWidget(widgets, BEGINNING_OF_LINE, this::beginningOfLine);
+        addBuiltinWidget(widgets, BEGINNING_OF_LINE_HIST, this::beginningOfLineHist);
+        addBuiltinWidget(widgets, CAPITALIZE_WORD, this::capitalizeWord);
+        addBuiltinWidget(widgets, CLEAR, this::clear);
+        addBuiltinWidget(widgets, CLEAR_SCREEN, this::clearScreen);
+        addBuiltinWidget(widgets, COMPLETE_PREFIX, this::completePrefix);
+        addBuiltinWidget(widgets, COMPLETE_WORD, this::completeWord);
+        addBuiltinWidget(widgets, COPY_PREV_WORD, this::copyPrevWord);
+        addBuiltinWidget(widgets, COPY_REGION_AS_KILL, this::copyRegionAsKill);
+        addBuiltinWidget(widgets, DELETE_CHAR, this::deleteChar);
+        addBuiltinWidget(widgets, DELETE_CHAR_OR_LIST, this::deleteCharOrList);
+        addBuiltinWidget(widgets, DELETE_WORD, this::deleteWord);
+        addBuiltinWidget(widgets, DIGIT_ARGUMENT, this::digitArgument);
+        addBuiltinWidget(widgets, DO_LOWERCASE_VERSION, this::doLowercaseVersion);
+        addBuiltinWidget(widgets, DOWN_CASE_WORD, this::downCaseWord);
+        addBuiltinWidget(widgets, DOWN_LINE, this::downLine);
+        addBuiltinWidget(widgets, DOWN_LINE_OR_HISTORY, this::downLineOrHistory);
+        addBuiltinWidget(widgets, DOWN_LINE_OR_SEARCH, this::downLineOrSearch);
+        addBuiltinWidget(widgets, DOWN_HISTORY, this::downHistory);
+        addBuiltinWidget(widgets, EMACS_EDITING_MODE, this::emacsEditingMode);
+        addBuiltinWidget(widgets, EMACS_BACKWARD_WORD, this::emacsBackwardWord);
+        addBuiltinWidget(widgets, EMACS_FORWARD_WORD, this::emacsForwardWord);
+        addBuiltinWidget(widgets, END_OF_BUFFER_OR_HISTORY, this::endOfBufferOrHistory);
+        addBuiltinWidget(widgets, END_OF_HISTORY, this::endOfHistory);
+        addBuiltinWidget(widgets, END_OF_LINE, this::endOfLine);
+        addBuiltinWidget(widgets, END_OF_LINE_HIST, this::endOfLineHist);
+        addBuiltinWidget(widgets, EXCHANGE_POINT_AND_MARK, this::exchangePointAndMark);
+        addBuiltinWidget(widgets, EXPAND_HISTORY, this::expandHistory);
+        addBuiltinWidget(widgets, EXPAND_OR_COMPLETE, this::expandOrComplete);
+        addBuiltinWidget(widgets, EXPAND_OR_COMPLETE_PREFIX, this::expandOrCompletePrefix);
+        addBuiltinWidget(widgets, EXPAND_WORD, this::expandWord);
+        addBuiltinWidget(widgets, FRESH_LINE, this::freshLine);
+        addBuiltinWidget(widgets, FORWARD_CHAR, this::forwardChar);
+        addBuiltinWidget(widgets, FORWARD_WORD, this::forwardWord);
+        addBuiltinWidget(widgets, HISTORY_INCREMENTAL_SEARCH_BACKWARD, this::historyIncrementalSearchBackward);
+        addBuiltinWidget(widgets, HISTORY_INCREMENTAL_SEARCH_FORWARD, this::historyIncrementalSearchForward);
+        addBuiltinWidget(widgets, HISTORY_SEARCH_BACKWARD, this::historySearchBackward);
+        addBuiltinWidget(widgets, HISTORY_SEARCH_FORWARD, this::historySearchForward);
+        addBuiltinWidget(widgets, INSERT_CLOSE_CURLY, this::insertCloseCurly);
+        addBuiltinWidget(widgets, INSERT_CLOSE_PAREN, this::insertCloseParen);
+        addBuiltinWidget(widgets, INSERT_CLOSE_SQUARE, this::insertCloseSquare);
+        addBuiltinWidget(widgets, INSERT_COMMENT, this::insertComment);
+        addBuiltinWidget(widgets, KILL_BUFFER, this::killBuffer);
+        addBuiltinWidget(widgets, KILL_LINE, this::killLine);
+        addBuiltinWidget(widgets, KILL_REGION, this::killRegion);
+        addBuiltinWidget(widgets, KILL_WHOLE_LINE, this::killWholeLine);
+        addBuiltinWidget(widgets, KILL_WORD, this::killWord);
+        addBuiltinWidget(widgets, LIST_CHOICES, this::listChoices);
+        addBuiltinWidget(widgets, MENU_COMPLETE, this::menuComplete);
+        addBuiltinWidget(widgets, MENU_EXPAND_OR_COMPLETE, this::menuExpandOrComplete);
+        addBuiltinWidget(widgets, NEG_ARGUMENT, this::negArgument);
+        addBuiltinWidget(widgets, OVERWRITE_MODE, this::overwriteMode);
+//        addBuiltinWidget(widgets, QUIT, this::quit);
+        addBuiltinWidget(widgets, QUOTED_INSERT, this::quotedInsert);
+        addBuiltinWidget(widgets, REDISPLAY, this::redisplay);
+        addBuiltinWidget(widgets, REDRAW_LINE, this::redrawLine);
+        addBuiltinWidget(widgets, REDO, this::redo);
+        addBuiltinWidget(widgets, SELF_INSERT, this::selfInsert);
+        addBuiltinWidget(widgets, SELF_INSERT_UNMETA, this::selfInsertUnmeta);
+        addBuiltinWidget(widgets, SEND_BREAK, this::sendBreak);
+        addBuiltinWidget(widgets, SET_MARK_COMMAND, this::setMarkCommand);
+        addBuiltinWidget(widgets, TRANSPOSE_CHARS, this::transposeChars);
+        addBuiltinWidget(widgets, TRANSPOSE_WORDS, this::transposeWords);
+        addBuiltinWidget(widgets, UNDEFINED_KEY, this::undefinedKey);
+        addBuiltinWidget(widgets, UNIVERSAL_ARGUMENT, this::universalArgument);
+        addBuiltinWidget(widgets, UNDO, this::undo);
+        addBuiltinWidget(widgets, UP_CASE_WORD, this::upCaseWord);
+        addBuiltinWidget(widgets, UP_HISTORY, this::upHistory);
+        addBuiltinWidget(widgets, UP_LINE, this::upLine);
+        addBuiltinWidget(widgets, UP_LINE_OR_HISTORY, this::upLineOrHistory);
+        addBuiltinWidget(widgets, UP_LINE_OR_SEARCH, this::upLineOrSearch);
+        addBuiltinWidget(widgets, VI_ADD_EOL, this::viAddEol);
+        addBuiltinWidget(widgets, VI_ADD_NEXT, this::viAddNext);
+        addBuiltinWidget(widgets, VI_BACKWARD_CHAR, this::viBackwardChar);
+        addBuiltinWidget(widgets, VI_BACKWARD_DELETE_CHAR, this::viBackwardDeleteChar);
+        addBuiltinWidget(widgets, VI_BACKWARD_BLANK_WORD, this::viBackwardBlankWord);
+        addBuiltinWidget(widgets, VI_BACKWARD_BLANK_WORD_END, this::viBackwardBlankWordEnd);
+        addBuiltinWidget(widgets, VI_BACKWARD_KILL_WORD, this::viBackwardKillWord);
+        addBuiltinWidget(widgets, VI_BACKWARD_WORD, this::viBackwardWord);
+        addBuiltinWidget(widgets, VI_BACKWARD_WORD_END, this::viBackwardWordEnd);
+        addBuiltinWidget(widgets, VI_BEGINNING_OF_LINE, this::viBeginningOfLine);
+        addBuiltinWidget(widgets, VI_CMD_MODE, this::viCmdMode);
+        addBuiltinWidget(widgets, VI_DIGIT_OR_BEGINNING_OF_LINE, this::viDigitOrBeginningOfLine);
+        addBuiltinWidget(widgets, VI_DOWN_LINE_OR_HISTORY, this::viDownLineOrHistory);
+        addBuiltinWidget(widgets, VI_CHANGE, this::viChange);
+        addBuiltinWidget(widgets, VI_CHANGE_EOL, this::viChangeEol);
+        addBuiltinWidget(widgets, VI_CHANGE_WHOLE_LINE, this::viChangeWholeLine);
+        addBuiltinWidget(widgets, VI_DELETE_CHAR, this::viDeleteChar);
+        addBuiltinWidget(widgets, VI_DELETE, this::viDelete);
+        addBuiltinWidget(widgets, VI_END_OF_LINE, this::viEndOfLine);
+        addBuiltinWidget(widgets, VI_KILL_EOL, this::viKillEol);
+        addBuiltinWidget(widgets, VI_FIRST_NON_BLANK, this::viFirstNonBlank);
+        addBuiltinWidget(widgets, VI_FIND_NEXT_CHAR, this::viFindNextChar);
+        addBuiltinWidget(widgets, VI_FIND_NEXT_CHAR_SKIP, this::viFindNextCharSkip);
+        addBuiltinWidget(widgets, VI_FIND_PREV_CHAR, this::viFindPrevChar);
+        addBuiltinWidget(widgets, VI_FIND_PREV_CHAR_SKIP, this::viFindPrevCharSkip);
+        addBuiltinWidget(widgets, VI_FORWARD_BLANK_WORD, this::viForwardBlankWord);
+        addBuiltinWidget(widgets, VI_FORWARD_BLANK_WORD_END, this::viForwardBlankWordEnd);
+        addBuiltinWidget(widgets, VI_FORWARD_CHAR, this::viForwardChar);
+        addBuiltinWidget(widgets, VI_FORWARD_WORD, this::viForwardWord);
+        addBuiltinWidget(widgets, VI_FORWARD_WORD, this::viForwardWord);
+        addBuiltinWidget(widgets, VI_FORWARD_WORD_END, this::viForwardWordEnd);
+        addBuiltinWidget(widgets, VI_HISTORY_SEARCH_BACKWARD, this::viHistorySearchBackward);
+        addBuiltinWidget(widgets, VI_HISTORY_SEARCH_FORWARD, this::viHistorySearchForward);
+        addBuiltinWidget(widgets, VI_INSERT, this::viInsert);
+        addBuiltinWidget(widgets, VI_INSERT_BOL, this::viInsertBol);
+        addBuiltinWidget(widgets, VI_INSERT_COMMENT, this::viInsertComment);
+        addBuiltinWidget(widgets, VI_JOIN, this::viJoin);
+        addBuiltinWidget(widgets, VI_KILL_LINE, this::viKillWholeLine);
+        addBuiltinWidget(widgets, VI_MATCH_BRACKET, this::viMatchBracket);
+        addBuiltinWidget(widgets, VI_OPEN_LINE_ABOVE, this::viOpenLineAbove);
+        addBuiltinWidget(widgets, VI_OPEN_LINE_BELOW, this::viOpenLineBelow);
+        addBuiltinWidget(widgets, VI_PUT_AFTER, this::viPutAfter);
+        addBuiltinWidget(widgets, VI_PUT_BEFORE, this::viPutBefore);
+        addBuiltinWidget(widgets, VI_REPEAT_FIND, this::viRepeatFind);
+        addBuiltinWidget(widgets, VI_REPEAT_SEARCH, this::viRepeatSearch);
+        addBuiltinWidget(widgets, VI_REPLACE_CHARS, this::viReplaceChars);
+        addBuiltinWidget(widgets, VI_REV_REPEAT_FIND, this::viRevRepeatFind);
+        addBuiltinWidget(widgets, VI_REV_REPEAT_SEARCH, this::viRevRepeatSearch);
+        addBuiltinWidget(widgets, VI_SWAP_CASE, this::viSwapCase);
+        addBuiltinWidget(widgets, VI_UP_LINE_OR_HISTORY, this::viUpLineOrHistory);
+        addBuiltinWidget(widgets, VI_YANK, this::viYankTo);
+        addBuiltinWidget(widgets, VI_YANK_WHOLE_LINE, this::viYankWholeLine);
+        addBuiltinWidget(widgets, VISUAL_LINE_MODE, this::visualLineMode);
+        addBuiltinWidget(widgets, VISUAL_MODE, this::visualMode);
+        addBuiltinWidget(widgets, WHAT_CURSOR_POSITION, this::whatCursorPosition);
+        addBuiltinWidget(widgets, YANK, this::yank);
+        addBuiltinWidget(widgets, YANK_POP, this::yankPop);
+        addBuiltinWidget(widgets, MOUSE, this::mouse);
+        addBuiltinWidget(widgets, BEGIN_PASTE, this::beginPaste);
+        addBuiltinWidget(widgets, FOCUS_IN, this::focusIn);
+        addBuiltinWidget(widgets, FOCUS_OUT, this::focusOut);
         return widgets;
     }
 
+    private void addBuiltinWidget(Map<String, Widget> widgets, String name, Widget widget) {
+        widgets.put(name, namedWidget(name, widget));
+    }
+
+    private Widget namedWidget(String name, Widget widget) {
+        return new Widget() {
+            @Override
+            public String toString() {
+                return name;
+            }
+            @Override
+            public boolean apply() {
+                return widget.apply();
+            }
+        };
+    }
+
     public boolean redisplay() {
         redisplay(true);
         return true;
     }
 
-    protected synchronized void redisplay(boolean flush) {
-        if (skipRedisplay) {
-            skipRedisplay = false;
-            return;
-        }
-
-        Status status = Status.getStatus(terminal, false);
-        if (status != null) {
-            status.redraw();
-        }
-
-        if (size.getRows() > 0 && size.getRows() < MIN_ROWS) {
-            AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH);
-
-            sb.append(prompt);
-            concat(getHighlightedBuffer(buf.toString()).columnSplitLength(Integer.MAX_VALUE), sb);
-            AttributedString full = sb.toAttributedString();
-
-            sb.setLength(0);
-            sb.append(prompt);
-            String line = buf.upToCursor();
-            if(maskingCallback != null) {
-                line = maskingCallback.display(line);
-            }
-
-            concat(new AttributedString(line).columnSplitLength(Integer.MAX_VALUE), sb);
-            AttributedString toCursor = sb.toAttributedString();
-
-            int w = WCWidth.wcwidth('\u2026');
-            int width = size.getColumns();
-            int cursor = toCursor.columnLength();
-            int inc = width /2 + 1;
-            while (cursor <= smallTerminalOffset + w) {
-                smallTerminalOffset -= inc;
-            }
-            while (cursor >= smallTerminalOffset + width - w) {
-                smallTerminalOffset += inc;
-            }
-            if (smallTerminalOffset > 0) {
+    protected void redisplay(boolean flush) {
+        try {
+            lock.lock();
+
+            if (skipRedisplay) {
+                skipRedisplay = false;
+                return;
+            }
+
+            Status status = Status.getStatus(terminal, false);
+            if (status != null) {
+                status.redraw();
+            }
+
+            if (size.getRows() > 0 && size.getRows() < MIN_ROWS) {
+                AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH);
+
+                sb.append(prompt);
+                concat(getHighlightedBuffer(buf.toString()).columnSplitLength(Integer.MAX_VALUE), sb);
+                AttributedString full = sb.toAttributedString();
+
                 sb.setLength(0);
-                sb.append("\u2026");
-                sb.append(full.columnSubSequence(smallTerminalOffset + w, Integer.MAX_VALUE));
-                full = sb.toAttributedString();
-            }
-            int length = full.columnLength();
-            if (length >= smallTerminalOffset + width) {
-                sb.setLength(0);
-                sb.append(full.columnSubSequence(0, width - w));
-                sb.append("\u2026");
-                full = sb.toAttributedString();
-            }
-
-            display.update(Collections.singletonList(full), cursor - smallTerminalOffset, flush);
-            return;
-        }
-
-        List<AttributedString> secondaryPrompts = new ArrayList<>();
-        AttributedString full = getDisplayedBufferWithPrompts(secondaryPrompts);
-
-        List<AttributedString> newLines;
-        if (size.getColumns() <= 0) {
-            newLines = new ArrayList<>();
-            newLines.add(full);
-        } else {
-            newLines = full.columnSplitLength(size.getColumns(), true, display.delayLineWrap());
-        }
-
-        List<AttributedString> rightPromptLines;
-        if (rightPrompt.length() == 0 || size.getColumns() <= 0) {
-            rightPromptLines = new ArrayList<>();
-        } else {
-            rightPromptLines = rightPrompt.columnSplitLength(size.getColumns());
-        }
-        while (newLines.size() < rightPromptLines.size()) {
-            newLines.add(new AttributedString(""));
-        }
-        for (int i = 0; i < rightPromptLines.size(); i++) {
-            AttributedString line = rightPromptLines.get(i);
-            newLines.set(i, addRightPrompt(line, newLines.get(i)));
-        }
-
-        int cursorPos = -1;
-        if (size.getColumns() > 0) {
-            AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH);
-            sb.append(prompt);
-            String buffer = buf.upToCursor();
-            if (maskingCallback != null) {
-                buffer = maskingCallback.display(buffer);
-            }
-            sb.append(insertSecondaryPrompts(new AttributedString(buffer), secondaryPrompts, false));
-            List<AttributedString> promptLines = sb.columnSplitLength(size.getColumns(), false, display.delayLineWrap());
-            if (!promptLines.isEmpty()) {
-                cursorPos = size.cursorPos(promptLines.size() - 1,
-                                           promptLines.get(promptLines.size() - 1).columnLength());
-            }
-        }
-
-        display.update(newLines, cursorPos, flush);
+                sb.append(prompt);
+                String line = buf.upToCursor();
+                if (maskingCallback != null) {
+                    line = maskingCallback.display(line);
+                }
+
+                concat(new AttributedString(line).columnSplitLength(Integer.MAX_VALUE), sb);
+                AttributedString toCursor = sb.toAttributedString();
+
+                int w = WCWidth.wcwidth('\u2026');
+                int width = size.getColumns();
+                int cursor = toCursor.columnLength();
+                int inc = width / 2 + 1;
+                while (cursor <= smallTerminalOffset + w) {
+                    smallTerminalOffset -= inc;
+                }
+                while (cursor >= smallTerminalOffset + width - w) {
+                    smallTerminalOffset += inc;
+                }
+                if (smallTerminalOffset > 0) {
+                    sb.setLength(0);
+                    sb.append("\u2026");
+                    sb.append(full.columnSubSequence(smallTerminalOffset + w, Integer.MAX_VALUE));
+                    full = sb.toAttributedString();
+                }
+                int length = full.columnLength();
+                if (length >= smallTerminalOffset + width) {
+                    sb.setLength(0);
+                    sb.append(full.columnSubSequence(0, width - w));
+                    sb.append("\u2026");
+                    full = sb.toAttributedString();
+                }
+
+                display.update(Collections.singletonList(full), cursor - smallTerminalOffset, flush);
+                return;
+            }
+
+            List<AttributedString> secondaryPrompts = new ArrayList<>();
+            AttributedString full = getDisplayedBufferWithPrompts(secondaryPrompts);
+
+            List<AttributedString> newLines;
+            if (size.getColumns() <= 0) {
+                newLines = new ArrayList<>();
+                newLines.add(full);
+            } else {
+                newLines = full.columnSplitLength(size.getColumns(), true, display.delayLineWrap());
+            }
+
+            List<AttributedString> rightPromptLines;
+            if (rightPrompt.length() == 0 || size.getColumns() <= 0) {
+                rightPromptLines = new ArrayList<>();
+            } else {
+                rightPromptLines = rightPrompt.columnSplitLength(size.getColumns());
+            }
+            while (newLines.size() < rightPromptLines.size()) {
+                newLines.add(new AttributedString(""));
+            }
+            for (int i = 0; i < rightPromptLines.size(); i++) {
+                AttributedString line = rightPromptLines.get(i);
+                newLines.set(i, addRightPrompt(line, newLines.get(i)));
+            }
+
+            int cursorPos = -1;
+            int cursorNewLinesId = -1;
+            int cursorColPos = -1;
+            if (size.getColumns() > 0) {
+                AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH);
+                sb.append(prompt);
+                String buffer = buf.upToCursor();
+                if (maskingCallback != null) {
+                    buffer = maskingCallback.display(buffer);
+                }
+                sb.append(insertSecondaryPrompts(new AttributedString(buffer), secondaryPrompts, false));
+                List<AttributedString> promptLines = sb.columnSplitLength(size.getColumns(), false, display.delayLineWrap());
+                if (!promptLines.isEmpty()) {
+                    cursorNewLinesId = promptLines.size() - 1;
+                    cursorColPos = promptLines.get(promptLines.size() - 1).columnLength();
+                    cursorPos = size.cursorPos(cursorNewLinesId, cursorColPos);
+                }
+            }
+
+            List<AttributedString> newLinesToDisplay = new ArrayList<>();
+            int displaySize = size.getRows() - (status != null ? status.size() : 0);
+            if (newLines.size() > displaySize && !isTerminalDumb()) {
+                StringBuilder sb = new StringBuilder(">....");
+                // blanks are needed when displaying command completion candidate list
+                for (int i = sb.toString().length(); i < size.getColumns(); i++) {
+                    sb.append(" ");
+                }
+                AttributedString partialCommandInfo = new AttributedString(sb.toString());
+                int lineId = newLines.size() - displaySize + 1;
+                int endId = displaySize;
+                int startId = 1;
+                if (lineId  > cursorNewLinesId) {
+                    lineId = cursorNewLinesId;
+                    endId = displaySize - 1;
+                    startId = 0;
+                } else {
+                    newLinesToDisplay.add(partialCommandInfo);
+                }
+                int cursorRowPos = 0;
+                for (int i = startId; i < endId; i++) {
+                    if (cursorNewLinesId == lineId) {
+                        cursorRowPos = i;
+                    }
+                    newLinesToDisplay.add(newLines.get(lineId++));
+                }
+                if (startId == 0) {
+                    newLinesToDisplay.add(partialCommandInfo);
+                }
+                cursorPos = size.cursorPos(cursorRowPos, cursorColPos);
+            } else {
+                newLinesToDisplay = newLines;
+            }
+            display.update(newLinesToDisplay, cursorPos, flush);
+        } finally {
+            lock.unlock();
+        }
     }
 
     private void concat(List<AttributedString> lines, AttributedStringBuilder sb) {
@@ -3656,26 +3841,26 @@
                 decode: while (true) {
                     ch = pattern.charAt(i++);
                     switch (ch) {
-                       case '{':
-                       case '}':
-                           String str = sb.toString();
-                           AttributedString astr;
-                           if (!isHidden) {
-                               astr = AttributedString.fromAnsi(str);
-                               cols += astr.columnLength();
-                           } else {
-                               astr = new AttributedString(str, AttributedStyle.HIDDEN);
-                           }
-                           if (padPartIndex == parts.size()) {
-                               padPartString = sb;
-                               if (i < plen) {
-                                   sb = new StringBuilder();
-                               }
-                           } else {
-                               sb.setLength(0);
-                           }
-                           parts.add(astr);
-                           isHidden = ch == '{';
+                        case '{':
+                        case '}':
+                            String str = sb.toString();
+                            AttributedString astr;
+                            if (!isHidden) {
+                                astr = AttributedString.fromAnsi(str);
+                                cols += astr.columnLength();
+                            } else {
+                                astr = new AttributedString(str, AttributedStyle.HIDDEN);
+                            }
+                            if (padPartIndex == parts.size()) {
+                                padPartString = sb;
+                                if (i < plen) {
+                                    sb = new StringBuilder();
+                                }
+                            } else {
+                                sb.setLength(0);
+                            }
+                            parts.add(astr);
+                            isHidden = ch == '{';
                             break decode;
                         case '%':
                             sb.append(ch);
@@ -4048,113 +4233,117 @@
         if (matching.isEmpty()) {
             return false;
         }
-
-        // If we only need to display the list, do it now
-        if (lst == CompletionType.List) {
+        size.copy(terminal.getSize());
+        try {
+            // If we only need to display the list, do it now
+            if (lst == CompletionType.List) {
+                List<Candidate> possible = matching.entrySet().stream()
+                        .flatMap(e -> e.getValue().stream())
+                        .collect(Collectors.toList());
+                doList(possible, line.word(), false, line::escape);
+                return !possible.isEmpty();
+            }
+
+            // Check if there's a single possible match
+            Candidate completion = null;
+            // If there's a single possible completion
+            if (matching.size() == 1) {
+                completion = matching.values().stream().flatMap(Collection::stream)
+                        .findFirst().orElse(null);
+            }
+            // Or if RECOGNIZE_EXACT is set, try to find an exact match
+            else if (isSet(Option.RECOGNIZE_EXACT)) {
+                completion = matching.values().stream().flatMap(Collection::stream)
+                        .filter(Candidate::complete)
+                        .filter(c -> exact.test(c.value()))
+                        .findFirst().orElse(null);
+            }
+            // Complete and exit
+            if (completion != null && !completion.value().isEmpty()) {
+                if (prefix) {
+                    buf.backspace(line.rawWordCursor());
+                } else {
+                    buf.move(line.rawWordLength() - line.rawWordCursor());
+                    buf.backspace(line.rawWordLength());
+                }
+                buf.write(line.escape(completion.value(), completion.complete()));
+                if (completion.complete()) {
+                    if (buf.currChar() != ' ') {
+                        buf.write(" ");
+                    } else {
+                        buf.move(1);
+                    }
+                }
+                if (completion.suffix() != null) {
+                    redisplay();
+                    Binding op = readBinding(getKeys());
+                    if (op != null) {
+                        String chars = getString(REMOVE_SUFFIX_CHARS, DEFAULT_REMOVE_SUFFIX_CHARS);
+                        String ref = op instanceof Reference ? ((Reference) op).name() : null;
+                        if (SELF_INSERT.equals(ref) && chars.indexOf(getLastBinding().charAt(0)) >= 0
+                                || ACCEPT_LINE.equals(ref)) {
+                            buf.backspace(completion.suffix().length());
+                            if (getLastBinding().charAt(0) != ' ') {
+                                buf.write(' ');
+                            }
+                        }
+                        pushBackBinding(true);
+                    }
+                }
+                return true;
+            }
+
             List<Candidate> possible = matching.entrySet().stream()
                     .flatMap(e -> e.getValue().stream())
                     .collect(Collectors.toList());
-            doList(possible, line.word(), false, line::escape);
-            return !possible.isEmpty();
-        }
-
-        // Check if there's a single possible match
-        Candidate completion = null;
-        // If there's a single possible completion
-        if (matching.size() == 1) {
-            completion = matching.values().stream().flatMap(Collection::stream)
-                    .findFirst().orElse(null);
-        }
-        // Or if RECOGNIZE_EXACT is set, try to find an exact match
-        else if (isSet(Option.RECOGNIZE_EXACT)) {
-            completion = matching.values().stream().flatMap(Collection::stream)
-                    .filter(Candidate::complete)
-                    .filter(c -> exact.test(c.value()))
-                    .findFirst().orElse(null);
-        }
-        // Complete and exit
-        if (completion != null && !completion.value().isEmpty()) {
+
+            if (useMenu) {
+                buf.move(line.word().length() - line.wordCursor());
+                buf.backspace(line.word().length());
+                doMenu(possible, line.word(), line::escape);
+                return true;
+            }
+
+            // Find current word and move to end
+            String current;
             if (prefix) {
-                buf.backspace(line.rawWordCursor());
+                current = line.word().substring(0, line.wordCursor());
             } else {
+                current = line.word();
                 buf.move(line.rawWordLength() - line.rawWordCursor());
+            }
+            // Now, we need to find the unambiguous completion
+            // TODO: need to find common suffix
+            String commonPrefix = null;
+            for (String key : matching.keySet()) {
+                commonPrefix = commonPrefix == null ? key : getCommonStart(commonPrefix, key, caseInsensitive);
+            }
+            boolean hasUnambiguous = commonPrefix.startsWith(current) && !commonPrefix.equals(current);
+
+            if (hasUnambiguous) {
                 buf.backspace(line.rawWordLength());
-            }
-            buf.write(line.escape(completion.value(), completion.complete()));
-            if (completion.complete()) {
-                if (buf.currChar() != ' ') {
-                    buf.write(" ");
-                } else {
-                    buf.move(1);
+                buf.write(line.escape(commonPrefix, false));
+                current = commonPrefix;
+                if ((!isSet(Option.AUTO_LIST) && isSet(Option.AUTO_MENU))
+                        || (isSet(Option.AUTO_LIST) && isSet(Option.LIST_AMBIGUOUS))) {
+                    if (!nextBindingIsComplete()) {
+                        return true;
+                    }
                 }
             }
-            if (completion.suffix() != null) {
-                redisplay();
-                Binding op = readBinding(getKeys());
-                if (op != null) {
-                    String chars = getString(REMOVE_SUFFIX_CHARS, DEFAULT_REMOVE_SUFFIX_CHARS);
-                    String ref = op instanceof Reference ? ((Reference) op).name() : null;
-                    if (SELF_INSERT.equals(ref) && chars.indexOf(getLastBinding().charAt(0)) >= 0
-                            || ACCEPT_LINE.equals(ref)) {
-                        buf.backspace(completion.suffix().length());
-                        if (getLastBinding().charAt(0) != ' ') {
-                            buf.write(' ');
-                        }
-                    }
-                    pushBackBinding(true);
-                }
-            }
-            return true;
-        }
-
-        List<Candidate> possible = matching.entrySet().stream()
-                .flatMap(e -> e.getValue().stream())
-                .collect(Collectors.toList());
-
-        if (useMenu) {
-            buf.move(line.word().length() - line.wordCursor());
-            buf.backspace(line.word().length());
-            doMenu(possible, line.word(), line::escape);
-            return true;
-        }
-
-        // Find current word and move to end
-        String current;
-        if (prefix) {
-            current = line.word().substring(0, line.wordCursor());
-        } else {
-            current = line.word();
-            buf.move(line.rawWordLength() - line.rawWordCursor());
-        }
-        // Now, we need to find the unambiguous completion
-        // TODO: need to find common suffix
-        String commonPrefix = null;
-        for (String key : matching.keySet()) {
-            commonPrefix = commonPrefix == null ? key : getCommonStart(commonPrefix, key, caseInsensitive);
-        }
-        boolean hasUnambiguous = commonPrefix.startsWith(current) && !commonPrefix.equals(current);
-
-        if (hasUnambiguous) {
-            buf.backspace(line.rawWordLength());
-            buf.write(line.escape(commonPrefix, false));
-            current = commonPrefix;
-            if ((!isSet(Option.AUTO_LIST) && isSet(Option.AUTO_MENU))
-                    || (isSet(Option.AUTO_LIST) && isSet(Option.LIST_AMBIGUOUS))) {
-                if (!nextBindingIsComplete()) {
+            if (isSet(Option.AUTO_LIST)) {
+                if (!doList(possible, current, true, line::escape)) {
                     return true;
                 }
             }
-        }
-        if (isSet(Option.AUTO_LIST)) {
-            if (!doList(possible, current, true, line::escape)) {
-                return true;
-            }
-        }
-        if (isSet(Option.AUTO_MENU)) {
-            buf.backspace(current.length());
-            doMenu(possible, line.word(), line::escape);
-        }
-        return true;
+            if (isSet(Option.AUTO_MENU)) {
+                buf.backspace(current.length());
+                doMenu(possible, line.word(), line::escape);
+            }
+            return true;
+        } finally {
+            size.copy(terminal.getBufferSize());
+        }
     }
 
     private CompletingParsedLine wrap(ParsedLine line) {
@@ -4534,7 +4723,7 @@
         if (listMax > 0 && possible.size() >= listMax
                 || lines >= size.getRows() - promptLines) {
             // prompt
-            post = () -> new AttributedString(getAppName() + ": do you wish to see to see all " + possible.size()
+            post = () -> new AttributedString(getAppName() + ": do you wish to see all " + possible.size()
                     + " possibilities (" + lines + " lines)?");
             redisplay(true);
             int c = readCharacter();
@@ -4586,7 +4775,7 @@
             }
             redisplay();
             // TODO: use a different keyMap ?
-            Binding b = bindingReader.readBinding(getKeys());
+            Binding b = doReadBinding(getKeys(), null);
             if (b instanceof Reference) {
                 String name = ((Reference) b).name();
                 if (BACKWARD_DELETE_CHAR.equals(name) || VI_BACKWARD_DELETE_CHAR.equals(name)) {
@@ -4731,7 +4920,7 @@
 
     @SuppressWarnings("unchecked")
     protected void toColumns(Object items, int width, int maxWidth, AttributedStringBuilder sb, Candidate selection, String completed, boolean rowsFirst, int[] out) {
-        if (maxWidth <= 0) {
+        if (maxWidth <= 0 || width <= 0) {
             return;
         }
         // This is a group
@@ -4985,7 +5174,9 @@
                 while (end < buf.length() && buf.atChar(end) != '\n') {
                     end++;
                 }
-                end++;
+                if (end < buf.length()) {
+                    end++;
+                }
             }
         }
         String killed = buf.substring(start, end);
@@ -5188,7 +5379,7 @@
         keyMap.bind(END_PASTE, BRACKETED_PASTE_END);
         StringBuilder sb = new StringBuilder();
         while (true) {
-            Object b = bindingReader.readBinding(keyMap);
+            Object b = doReadBinding(keyMap, null);
             if (b == END_PASTE) {
                 break;
             }
@@ -5227,6 +5418,11 @@
      */
     public boolean clearScreen() {
         if (terminal.puts(Capability.clear_screen)) {
+            // ConEMU extended fonts support
+            if (AbstractWindowsTerminal.TYPE_WINDOWS_CONEMU.equals(terminal.getType())
+                    && !Boolean.getBoolean("org.jline.terminal.conemu.disable-activate")) {
+                terminal.writer().write("\u001b[9999E");
+            }
             Status status = Status.getStatus(terminal, false);
             if (status != null) {
                 status.reset();
@@ -5358,6 +5554,7 @@
 
     public KeyMap<Binding> emacs() {
         KeyMap<Binding> emacs = new KeyMap<>();
+        bindKeys(emacs);
         bind(emacs, SET_MARK_COMMAND,                       ctrl('@'));
         bind(emacs, BEGINNING_OF_LINE,                      ctrl('A'));
         bind(emacs, BACKWARD_CHAR,                          ctrl('B'));
@@ -5372,6 +5569,7 @@
         bind(emacs, CLEAR_SCREEN,                           ctrl('L'));
         bind(emacs, ACCEPT_LINE,                            ctrl('M'));
         bind(emacs, DOWN_LINE_OR_HISTORY,                   ctrl('N'));
+        bind(emacs, ACCEPT_LINE_AND_DOWN_HISTORY,           ctrl('O'));
         bind(emacs, UP_LINE_OR_HISTORY,                     ctrl('P'));
         bind(emacs, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('R'));
         bind(emacs, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('S'));
@@ -5415,6 +5613,7 @@
         bind(emacs, END_OF_HISTORY,                         alt('>'));
         bind(emacs, LIST_CHOICES,                           alt('?'));
         bind(emacs, DO_LOWERCASE_VERSION,                   range("^[A-^[Z"));
+        bind(emacs, ACCEPT_AND_HOLD,                        alt('a'));
         bind(emacs, BACKWARD_WORD,                          alt('b'));
         bind(emacs, CAPITALIZE_WORD,                        alt('c'));
         bind(emacs, KILL_WORD,                              alt('d'));
@@ -5439,6 +5638,7 @@
 
     public KeyMap<Binding> viInsertion() {
         KeyMap<Binding> viins = new KeyMap<>();
+        bindKeys(viins);
         bind(viins, SELF_INSERT,                            range("^@-^_"));
         bind(viins, LIST_CHOICES,                           ctrl('D'));
         bind(viins, SEND_BREAK,                             ctrl('G'));
@@ -5638,6 +5838,14 @@
         return KeyMap.key(terminal, capability);
     }
 
+    private void bindKeys(KeyMap<Binding> emacs) {
+        Widget beep = namedWidget("beep", this::beep);
+        Stream.of(Capability.values())
+                .filter(c -> c.name().startsWith("key_"))
+                .map(this::key)
+                .forEach(k -> bind(emacs, beep, k));
+    }
+
     private void bindArrowKeys(KeyMap<Binding> map) {
         bind(map, UP_LINE_OR_SEARCH,    key(Capability.key_up));
         bind(map, DOWN_LINE_OR_SEARCH,  key(Capability.key_down));
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/SimpleMaskingCallback.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/SimpleMaskingCallback.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/UndoTree.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/UndoTree.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/AggregateCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/AggregateCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/ArgumentCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/ArgumentCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/EnumCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/EnumCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/FileNameCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/FileNameCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/NullCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/NullCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.completer;
 
@@ -43,6 +43,11 @@
         }
     }
 
+    public StringsCompleter(Candidate ... candidates) {
+        assert candidates != null;
+        this.candidates.addAll(Arrays.asList(candidates));
+    }
+
     public void complete(LineReader reader, final ParsedLine commandLine, final List<Candidate> candidates) {
         assert commandLine != null;
         assert candidates != null;
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/package-info.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/package-info.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 /**
  * JLine 3.
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,12 +4,13 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.reader.impl.history;
 
 import java.io.*;
 import java.nio.file.*;
+import java.time.DateTimeException;
 import java.time.Instant;
 import java.util.*;
 
@@ -36,8 +37,7 @@
 
     private LineReader reader;
 
-    private int lastLoaded = 0;
-    private int nbEntriesInFile = 0;
+    private Map<String, HistoryFileData> historyFiles = new HashMap<>();
     private int offset = 0;
     private int index = 0;
 
@@ -68,7 +68,7 @@
             try {
                 load();
             }
-            catch (IOException e) {
+            catch (IllegalArgumentException | IOException e) {
                 Log.warn("Failed to load history", e);
             }
         }
@@ -84,12 +84,11 @@
                     try (BufferedReader reader = Files.newBufferedReader(path)) {
                         internalClear();
                         reader.lines().forEach(line -> addHistoryLine(path, line));
-                        lastLoaded = items.size();
-                        nbEntriesInFile = lastLoaded;
+                        setHistoryFileData(path, new HistoryFileData(items.size(), items.size()));
                         maybeResize();
                     }
                 }
-            } catch (IOException e) {
+            } catch (IllegalArgumentException | IOException e) {
                 Log.debug("Failed to load history; clearing", e);
                 internalClear();
                 throw e;
@@ -97,20 +96,100 @@
         }
     }
 
+    @Override
+    public void read(Path file, boolean incremental) 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));
+                        setHistoryFileData(path, new HistoryFileData(items.size(), items.size()));
+                        maybeResize();
+                    }
+                }
+            } catch (IllegalArgumentException | IOException e) {
+                Log.debug("Failed to read history; clearing", e);
+                internalClear();
+                throw e;
+            }
+        }
+    }
+
+    private String doHistoryFileDataKey (Path path){
+        return path != null ? path.toAbsolutePath().toString() : null;
+    }
+
+    private HistoryFileData getHistoryFileData(Path path) {
+        String key = doHistoryFileDataKey(path);
+        if (!historyFiles.containsKey(key)){
+            historyFiles.put(key, new HistoryFileData());
+        }
+        return historyFiles.get(key);
+    }
+
+    private void setHistoryFileData(Path path, HistoryFileData historyFileData) {
+        historyFiles.put(doHistoryFileDataKey(path), historyFileData);
+    }
+
+    private boolean isLineReaderHistory (Path path) throws IOException {
+        Path lrp = getPath();
+        if (lrp == null) {
+            if (path != null) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return Files.isSameFile(lrp, path);
+    }
+
+    private void setLastLoaded(Path path, int lastloaded){
+        getHistoryFileData(path).setLastLoaded(lastloaded);
+    }
+
+    private void setEntriesInFile(Path path, int entriesInFile){
+        getHistoryFileData(path).setEntriesInFile(entriesInFile);
+    }
+
+    private void incEntriesInFile(Path path, int amount){
+        getHistoryFileData(path).incEntriesInFile(amount);
+    }
+
+    private int getLastLoaded(Path path){
+        return getHistoryFileData(path).getLastLoaded();
+    }
+
+    private int getEntriesInFile(Path path){
+        return getHistoryFileData(path).getEntriesInFile();
+    }
+
     protected void addHistoryLine(Path path, String line) {
+        addHistoryLine(path, line, false);
+    }
+
+    protected void addHistoryLine(Path path, String line, boolean checkDuplicates) {
         if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
             int idx = line.indexOf(':');
+            final String badHistoryFileSyntax = "Bad history file syntax! " +
+                "The history file `" + path + "` may be an older history: " +
+                "please remove it or use a different history file.";
             if (idx < 0) {
-                throw new IllegalArgumentException("Bad history file syntax! " +
-                        "The history file `" + path + "` may be an older history: " +
-                        "please remove it or use a different history file.");
+                throw new IllegalArgumentException(badHistoryFileSyntax);
             }
-            Instant time = Instant.ofEpochMilli(Long.parseLong(line.substring(0, idx)));
+            Instant time;
+            try {
+                time = Instant.ofEpochMilli(Long.parseLong(line.substring(0, idx)));
+            } catch (DateTimeException | NumberFormatException e) {
+                throw new IllegalArgumentException(badHistoryFileSyntax);
+            }
+
             String unescaped = unescape(line.substring(idx + 1));
-            internalAdd(time, unescaped);
+            internalAdd(time, unescaped, checkDuplicates);
         }
         else {
-            internalAdd(Instant.now(), unescape(line));
+            internalAdd(Instant.now(), unescape(line), checkDuplicates);
         }
     }
 
@@ -125,28 +204,45 @@
     }
 
     @Override
+    public void write(Path file, boolean incremental) throws IOException {
+        Path path = file != null ? file : getPath();
+        if (path != null && Files.exists(path)) {
+            path.toFile().delete();
+        }
+        internalWrite(path, incremental ? getLastLoaded(path) : 0);
+    }
+
+    @Override
+    public void append(Path file, boolean incremental) throws IOException {
+        internalWrite(file != null ? file : getPath(),
+                      incremental ? getLastLoaded(file) : 0);
+    }
+
+    @Override
     public void save() throws IOException {
-        Path path = getPath();
+        internalWrite(getPath(), getLastLoaded(getPath()));
+    }
+
+    private void internalWrite(Path path, int from) throws IOException {
         if (path != null) {
             Log.trace("Saving history to: ", path);
             Files.createDirectories(path.toAbsolutePath().getParent());
             // Append new items to the history file
             try (BufferedWriter writer = Files.newBufferedWriter(path.toAbsolutePath(),
               StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
-                for (Entry entry : items.subList(lastLoaded, items.size())) {
+                for (Entry entry : items.subList(from, items.size())) {
                     if (isPersistable(entry)) {
                         writer.append(format(entry));
                     }
                 }
             }
-            nbEntriesInFile += items.size() - lastLoaded;
-            // If we are over 25% max size, trim history file
+            incEntriesInFile(path, items.size() - from);
             int max = getInt(reader, LineReader.HISTORY_FILE_SIZE, DEFAULT_HISTORY_FILE_SIZE);
-            if (nbEntriesInFile > max + max / 4) {
+            if (getEntriesInFile(path) > max + max / 4) {
                 trimHistory(path, max);
             }
         }
-        lastLoaded = items.size();
+        setLastLoaded(path, items.size());
     }
 
     protected void trimHistory(Path path, int max) throws IOException {
@@ -172,11 +268,14 @@
         }
         Files.move(temp, path, StandardCopyOption.REPLACE_EXISTING);
         // Keep items in memory
-        internalClear();
-        offset = allItems.get(0).index();
-        items.addAll(allItems);
-        lastLoaded = items.size();
-        nbEntriesInFile = items.size();
+        if (isLineReaderHistory(path)) {
+            internalClear();
+            offset = allItems.get(0).index();
+            items.addAll(allItems);
+            setHistoryFileData(path, new HistoryFileData(items.size(), items.size()));
+        } else {
+            setEntriesInFile(path, allItems.size());
+        }
         maybeResize();
     }
 
@@ -194,8 +293,7 @@
     private void internalClear() {
         offset = 0;
         index = 0;
-        lastLoaded = 0;
-        nbEntriesInFile = 0;
+        historyFiles = new HashMap<>();
         items.clear();
     }
 
@@ -302,7 +400,18 @@
     }
 
     protected void internalAdd(Instant time, String line) {
+        internalAdd(time, line, false);
+    }
+
+    protected void internalAdd(Instant time, String line, boolean checkDuplicates) {
         Entry entry = new EntryImpl(offset + items.size(), time, line);
+        if (checkDuplicates) {
+            for (Entry e: items) {
+                if (e.line().trim().equals(line.trim())) {
+                    return;
+                }
+            }
+        }
         items.add(entry);
         maybeResize();
     }
@@ -310,7 +419,9 @@
     private void maybeResize() {
         while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) {
             items.removeFirst();
-            lastLoaded--;
+            for (HistoryFileData hfd: historyFiles.values()) {
+                hfd.decLastLoaded();
+            }
             offset++;
         }
         index = size();
@@ -503,5 +614,46 @@
         return sb.toString();
     }
 
+    private class HistoryFileData {
+        private int lastLoaded = 0;
+        private int entriesInFile = 0;
+
+        public HistoryFileData() {
+        }
+
+        public HistoryFileData(int lastLoaded, int entriesInFile) {
+            this.lastLoaded = lastLoaded;
+            this.entriesInFile = entriesInFile;
+        }
+
+        public int getLastLoaded() {
+            return lastLoaded;
+        }
+
+        public void setLastLoaded(int lastLoaded) {
+            this.lastLoaded = lastLoaded;
+        }
+
+        public void decLastLoaded() {
+            lastLoaded = lastLoaded - 1;
+            if (lastLoaded < 0) {
+                lastLoaded = 0;
+            }
+        }
+
+        public int getEntriesInFile() {
+            return entriesInFile;
+        }
+
+        public void setEntriesInFile(int entriesInFile) {
+            this.entriesInFile = entriesInFile;
+        }
+
+        public void incEntriesInFile(int amount) {
+            entriesInFile = entriesInFile + amount;
+        }
+
+    }
+
 }
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/package-info.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/package-info.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 /**
  * JLine 3.
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/package-info.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/package-info.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 /**
  * JLine 3.
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Attributes.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Attributes.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Cursor.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Cursor.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/MouseEvent.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/MouseEvent.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Size.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Size.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
@@ -111,7 +111,7 @@
      *
      * @return The output stream
      *
-     * @see #writer();
+     * @see #writer()
      */
     OutputStream output();
 
@@ -183,6 +183,11 @@
 
     void setAttributes(Attributes attr);
 
+    /**
+     * Retrieve the size of the visible window
+     * @return the visible terminal size
+     * @see #getBufferSize()
+     */
     Size getSize();
 
     void setSize(Size size);
@@ -195,6 +200,22 @@
         return getSize().getRows();
     }
 
+    /**
+     * Retrieve the size of the window buffer.
+     * Some terminals can be configured to have a buffer size
+     * larger than the visible window size and provide scroll bars.
+     * In such cases, this method should attempt to return the size
+     * of the whole buffer.  The <code>getBufferSize()</code> method
+     * can be used to avoid wrapping when using the terminal in a line
+     * editing mode, while the {@link #getSize()} method should be
+     * used when using full screen mode.
+     * @return the terminal buffer size
+     * @see #getSize()
+     */
+    default Size getBufferSize() {
+        return getSize();
+    }
+
     void flush();
 
     //
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2018, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal;
 
@@ -33,9 +33,6 @@
 import jdk.internal.org.jline.utils.Log;
 import jdk.internal.org.jline.utils.OSUtils;
 
-import static jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal.TYPE_WINDOWS;
-import static jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR;
-
 /**
  * Builder class to create terminals.
  */
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPosixTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPosixTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPty.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPty.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,3 +1,11 @@
+/*
+ * 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;
 
 import jdk.internal.org.jline.terminal.Attributes;
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsConsoleWriter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsConsoleWriter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2018, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
@@ -21,12 +21,10 @@
 import jdk.internal.org.jline.utils.Signals;
 import jdk.internal.org.jline.utils.WriterOutputStream;
 
-import java.io.IOError;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
@@ -50,6 +48,7 @@
 
     public static final String TYPE_WINDOWS = "windows";
     public static final String TYPE_WINDOWS_256_COLOR = "windows-256color";
+    public static final String TYPE_WINDOWS_CONEMU = "windows-conemu";
     public static final String TYPE_WINDOWS_VTP = "windows-vtp";
 
     public static final int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
@@ -110,7 +109,7 @@
         closer = this::close;
         ShutdownHooks.add(closer);
         // ConEMU extended fonts support
-        if (TYPE_WINDOWS_256_COLOR.equals(getType())
+        if (TYPE_WINDOWS_CONEMU.equals(getType())
                 && !Boolean.getBoolean("org.jline.terminal.conemu.disable-activate")) {
             writer.write("\u001b[9999E");
             writer.flush();
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/CursorSupport.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/CursorSupport.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/DumbTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/DumbTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExecPty.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExecPty.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2019, the original author or authors.
+ * Copyright (c) 2002-2016, 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
@@ -137,15 +137,12 @@
         }
         String undef = System.getProperty("os.name").toLowerCase().startsWith("hp") ? "^-" : "undef";
         for (ControlChar cchar : ControlChar.values()) {
-            if (attr.getControlChar(cchar) != current.getControlChar(cchar)) {
+            int v = attr.getControlChar(cchar);
+            if (v >= 0 && v != current.getControlChar(cchar)) {
                 String str = "";
-                int v = attr.getControlChar(cchar);
-                if (v == -1) { // Skip if ControlChar is <UNDEF>
-                    continue;
-                }
                 commands.add(cchar.name().toLowerCase().substring(1));
                 if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) {
-                    commands.add(Integer.toBinaryString(v));
+                    commands.add(Integer.toString(v));
                 }
                 else if (v == 0) {
                     commands.add(undef);
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExternalTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExternalTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/LineDisciplineTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/LineDisciplineTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/MouseSupport.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/MouseSupport.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/NativeSignalHandler.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/NativeSignalHandler.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixPtyTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixPtyTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixSysTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixSysTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/package-info.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/package-info.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 /**
  * JLine 3.
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,3 +1,11 @@
+/*
+ * 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.spi;
 
 import jdk.internal.org.jline.terminal.Attributes;
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,3 +1,11 @@
+/*
+ * 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.spi;
 
 import jdk.internal.org.jline.terminal.Attributes;
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/Pty.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/Pty.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.spi;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2016, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
@@ -38,6 +38,14 @@
     // cache the value here as we can't afford to get it each time
     static final boolean DISABLE_ALTERNATE_CHARSET = Boolean.getBoolean(PROP_DISABLE_ALTERNATE_CHARSET);
 
+    public void print(Terminal terminal) {
+        terminal.writer().print(toAnsi(terminal));
+    }
+
+    public void println(Terminal terminal) {
+        terminal.writer().println(toAnsi(terminal));
+    }
+
     public String toAnsi() {
         return toAnsi(null);
     }
@@ -54,7 +62,8 @@
             if (max_colors != null) {
                 colors = max_colors;
             }
-            force256colors = AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR.equals(terminal.getType());
+            force256colors = AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR.equals(terminal.getType())
+                || AbstractWindowsTerminal.TYPE_WINDOWS_CONEMU.equals(terminal.getType());
             if (!DISABLE_ALTERNATE_CHARSET) {
                 alternateIn = Curses.tputs(terminal.getStringCapability(Capability.enter_alt_charset_mode));
                 alternateOut = Curses.tputs(terminal.getStringCapability(Capability.exit_alt_charset_mode));
@@ -293,7 +302,7 @@
             if (col + w > start) {
                 break;
             }
-            begin++;
+            begin += Character.charCount(cp);
             col += w;
         }
         int end = begin;
@@ -305,7 +314,7 @@
             if (col + w > stop) {
                 break;
             }
-            end++;
+            end += Character.charCount(cp);
             col += w;
         }
         return subSequence(begin, end);
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,12 +4,13 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
 import java.security.InvalidParameterException;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -98,6 +99,10 @@
     }
 
     public static AttributedString fromAnsi(String ansi, int tabs) {
+        return fromAnsi(ansi, Arrays.asList(tabs));
+    }
+
+    public static AttributedString fromAnsi(String ansi, List<Integer> tabs) {
         if (ansi == null) {
             return null;
         }
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,11 +4,13 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.regex.Matcher;
@@ -24,7 +26,7 @@
     private char[] buffer;
     private int[] style;
     private int length;
-    private int tabs = 0;
+    private TabStops tabs = new TabStops(0);
     private int lastLineLength = 0;
     private AttributedStyle current = AttributedStyle.DEFAULT;
 
@@ -151,7 +153,7 @@
         for (int i = start; i < end; i++) {
             char c = str.charAt(i);
             int s = str.styleCodeAt(i) & ~current.getMask() | current.getStyle();
-            if (tabs > 0 && c == '\t') {
+            if (tabs.defined() && c == '\t') {
                 insertTab(new AttributedStyle(s, 0));
             } else {
                 ensureCapacity(length + 1);
@@ -332,7 +334,7 @@
                     // This is not a SGR code, so ignore
                     ansiState = 0;
                 }
-            } else if (c == '\t' && tabs > 0) {
+            } else if (c == '\t' && tabs.defined()) {
                 insertTab(current);
             } else {
                 ensureCapacity(length + 1);
@@ -350,7 +352,7 @@
     }
 
     protected void insertTab(AttributedStyle s) {
-        int nb = tabs - lastLineLength % tabs;
+        int nb = tabs.spaces(lastLineLength);
         ensureCapacity(length + nb);
         for (int i = 0; i < nb; i++) {
             buffer[length] = ' ';
@@ -373,13 +375,17 @@
      * @return this
      */
     public AttributedStringBuilder tabs(int tabsize) {
+        if (tabsize < 0) {
+            throw new IllegalArgumentException("Tab size must be non negative");
+        }
+        return tabs(Arrays.asList(tabsize));
+    }
+
+    public AttributedStringBuilder tabs(List<Integer> tabs) {
         if (length > 0) {
             throw new IllegalStateException("Cannot change tab size after appending text");
         }
-        if (tabsize < 0) {
-            throw new IllegalArgumentException("Tab size must be non negative");
-        }
-        this.tabs = tabsize;
+        this.tabs = new TabStops(tabs);
         return this;
     }
 
@@ -393,4 +399,60 @@
         return this;
     }
 
+    public AttributedStringBuilder styleMatches(Pattern pattern, List<AttributedStyle> styles) {
+        Matcher matcher = pattern.matcher(this);
+        while (matcher.find()) {
+            for (int group = 0; group < matcher.groupCount(); group++) {
+                AttributedStyle s = styles.get(group);
+                for (int i = matcher.start(group + 1); i < matcher.end(group + 1); i++) {
+                    style[i] = (style[i] & ~s.getMask()) | s.getStyle();
+                }
+            }
+        }
+        return this;
+    }
+
+    private class TabStops {
+        private List<Integer> tabs = new ArrayList<>();
+        private int lastStop = 0;
+        private int lastSize = 0;
+
+        public TabStops(int tabs) {
+            this.lastSize = tabs;
+        }
+
+        public TabStops(List<Integer> tabs) {
+            this.tabs = tabs;
+            int p = 0;
+            for (int s: tabs) {
+                if (s <= p) {
+                    continue;
+                }
+                lastStop = s;
+                lastSize = s - p;
+                p = s;
+            }
+        }
+
+        boolean defined() {
+            return lastSize > 0;
+        }
+
+        int spaces(int lastLineLength) {
+            int out = 0;
+            if (lastLineLength >= lastStop) {
+                out = lastSize - (lastLineLength - lastStop) % lastSize;
+            } else {
+                for (int s: tabs) {
+                    if (s > lastLineLength) {
+                        out = s - lastLineLength;
+                        break;
+                    }
+                }
+            }
+            return out;
+        }
+
+    }
+
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ClosedException.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ClosedException.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
@@ -74,8 +74,16 @@
             switch (ch) {
                 case '\\':
                     ch = str.charAt(index++);
-                    if (ch >= '0' && ch <= '9') {
-                        throw new UnsupportedOperationException(); // todo
+                    if (ch >= '0' && ch <= '7') {
+                        int val = ch - '0';
+                        for (int i = 0; i < 2; i++) {
+                            ch = str.charAt(index++);
+                            if (ch < '0' || ch > '7') {
+                                throw new IllegalStateException();
+                            }
+                            val = val * 8 + (ch - '0');
+                        }
+                        out.append((char) val);
                     } else {
                         switch (ch) {
                             case 'e':
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/DiffHelper.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/DiffHelper.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
@@ -492,7 +492,7 @@
     }
 
     void rawPrint(AttributedString str) {
-        terminal.writer().write(str.toAnsi(terminal));
+        str.print(terminal);
     }
 
     public int wcwidth(String str) {
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ExecHelper.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ExecHelper.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2016, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
@@ -578,6 +578,8 @@
                     int iVal;
                     if (val.startsWith("0x")) {
                         iVal = Integer.parseInt(val.substring(2), 16);
+                    } else if (val.startsWith("0")) {
+                        iVal = Integer.parseInt(val.substring(1), 8);
                     } else {
                         iVal = Integer.parseInt(val);
                     }
@@ -614,7 +616,7 @@
 
     static {
         for (String s : Arrays.asList("dumb", "ansi", "xterm", "xterm-256color",
-                                      "windows", "windows-256color", "windows-vtp",
+                                      "windows", "windows-256color", "windows-conemu", "windows-vtp",
                                       "screen", "screen-256color")) {
             setDefaultInfoCmp(s, () -> loadDefaultInfoCmp(s));
         }
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InputStreamReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InputStreamReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Levenshtein.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Levenshtein.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlocking.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlocking.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStream.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStream.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStreamImpl.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStreamImpl.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReaderImpl.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReaderImpl.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ShutdownHooks.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ShutdownHooks.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,10 +4,11 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Proxy;
 import java.util.Objects;
 
@@ -85,13 +86,16 @@
 
     private static Object doRegister(String name, Object handler) throws Exception {
         Log.trace(() -> "Registering signal " + name + " with handler " + toString(handler));
-        if ("QUIT".equals(name) || "INFO".equals(name) && "9".equals(System.getProperty("java.specification.version"))) {
+        Class<?> signalClass = Class.forName("sun.misc.Signal");
+        Constructor<?> constructor = signalClass.getConstructor(String.class);
+        Object signal;
+        try {
+            signal = constructor.newInstance(name);
+        } catch (IllegalArgumentException e) {
             Log.trace(() -> "Ignoring unsupported signal " + name);
             return null;
         }
-        Class<?> signalClass = Class.forName("sun.misc.Signal");
         Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
-        Object signal = signalClass.getConstructor(String.class).newInstance(name);
         return signalClass.getMethod("handle", signalClass, signalHandlerClass)
                 .invoke(null, signal, handler);
     }
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Status.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Status.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
@@ -24,9 +24,11 @@
     protected final AbstractTerminal terminal;
     protected final boolean supported;
     protected List<AttributedString> oldLines = Collections.emptyList();
+    protected List<AttributedString> linesToRestore = Collections.emptyList();
     protected int rows;
     protected int columns;
     protected boolean force;
+    protected boolean suspended = false;
 
     public static Status getStatus(Terminal terminal) {
         return getStatus(terminal, true);
@@ -61,15 +63,34 @@
         this.force = true;
     }
 
+    public void hardReset() {
+        if (suspended) {
+            return;
+        }
+        List<AttributedString> lines = new ArrayList<>(oldLines);
+        update(null);
+        update(lines);
+    }
+
     public void redraw() {
+        if (suspended) {
+            return;
+        }
         update(oldLines);
     }
 
     public void update(List<AttributedString> lines) {
+        if (!supported) {
+            return;
+        }
         if (lines == null) {
             lines = Collections.emptyList();
         }
-        if (!supported || (oldLines.equals(lines) && !force)) {
+        if (suspended) {
+            linesToRestore = new ArrayList<>(lines);
+            return;
+        }
+        if (oldLines.equals(lines) && !force) {
             return;
         }
         int nb = lines.size() - oldLines.size();
@@ -82,10 +103,11 @@
             }
         }
         terminal.puts(Capability.save_cursor);
+        terminal.puts(Capability.cursor_address, rows - lines.size(), 0);
         terminal.puts(Capability.clr_eos);
         for (int i = 0; i < lines.size(); i++) {
             terminal.puts(Capability.cursor_address, rows - lines.size() + i, 0);
-            terminal.writer().write(lines.get(i).columnSubSequence(0, columns).toAnsi(terminal));
+            lines.get(i).columnSubSequence(0, columns).print(terminal);
         }
         terminal.puts(Capability.change_scroll_region, 0, rows - 1 - lines.size());
         terminal.puts(Capability.restore_cursor);
@@ -93,4 +115,27 @@
         oldLines = new ArrayList<>(lines);
         force = false;
     }
+
+    public void suspend() {
+        if (suspended) {
+            return;
+        }
+        linesToRestore = new ArrayList<>(oldLines);
+        update(null);
+        suspended = true;
+    }
+
+    public void restore() {
+        if (!suspended) {
+            return;
+        }
+        suspended = false;
+        update(linesToRestore);
+        linesToRestore = Collections.emptyList();
+    }
+
+    public int size() {
+        return oldLines.size();
+    }
+
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WCWidth.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WCWidth.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WriterOutputStream.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WriterOutputStream.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.utils;
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/capabilities.txt	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/capabilities.txt	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
 # This software is distributable under the BSD license. See the terms of the
 # BSD license in the documentation provided with this software.
 #
-# http://www.opensource.org/licenses/bsd-license.php
+# https://opensource.org/licenses/BSD-3-Clause
 #
 
 auto_left_margin, bw, bw
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/colors.txt	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/colors.txt	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
 # This software is distributable under the BSD license. See the terms of the
 # BSD license in the documentation provided with this software.
 #
-# http://www.opensource.org/licenses/bsd-license.php
+# https://opensource.org/licenses/BSD-3-Clause
 #
 
 black
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/dumb-colors.caps	Mon Nov 04 09:40:35 2019 +0100
@@ -0,0 +1,4 @@
+dumb-color|80-column dumb tty with 256 coors,
+        am,
+        colors#256, cols#80,
+        bel=^G, cr=^M, cud1=^J, ind=^J,
--- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/package-info.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/package-info.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 /**
  * JLine 3.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-conemu.caps	Mon Nov 04 09:40:35 2019 +0100
@@ -0,0 +1,27 @@
+windows-conemu|conemu windows terminal,
+	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,
+	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,
+	dl=\E[%p1%dM, dl1=\E[M,
+	ech=\E[%p1%dX,
+	el=\E[K, ed=\E[2K,
+	el1=\E[1K, home=\E[H, hpa=\E[%i%p1%dG,
+	ind=^J,
+	invis=\E[8m, kbs=^H, kcbt=\E[Z,
+	kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+	khome=\E[H,
+	op=\E[39;49m,
+	rev=\E[7m,
+	rmacs=\E[10m, rmpch=\E[10m, rmso=\E[m, rmul=\E[m,
+	setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+	sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m,
+	sgr0=\E[0;10m,
+	smso=\E[7m,
+	smul=\E[4m,
+	kdch1=\E[3~, kich1=\E[2~, kend=\E[4~, knp=\E[6~, kpp=\E[5~,
+	kf1=\EOP, kf2=\EOQ, kf3=\EOR, kf4=\EOS, kf5=\E[15~, kf6=\E[17~,
+	kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~,
--- a/src/jdk.internal.le/share/legal/jline.md	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/share/legal/jline.md	Mon Nov 04 09:40:35 2019 +0100
@@ -1,4 +1,4 @@
-## JLine v3.9.0
+## JLine v3.12.1
 
 ### JLine License
 <pre>
--- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,3 +1,11 @@
+/*
+ * 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.terminal.impl.jna;
 
 import jdk.internal.org.jline.terminal.Attributes;
--- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinConsoleWriter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinConsoleWriter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl.jna.win;
 
--- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java	Mon Nov 04 09:40:35 2019 +0100
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2002-2018, the original author or authors.
+ * 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.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl.jna.win;
 
@@ -36,7 +36,7 @@
         Writer writer;
         if (ansiPassThrough) {
             if (type == null) {
-                type = OSUtils.IS_CONEMU ? TYPE_WINDOWS_256_COLOR : TYPE_WINDOWS;
+                type = OSUtils.IS_CONEMU ? TYPE_WINDOWS_CONEMU : TYPE_WINDOWS;
             }
             writer = new JnaWinConsoleWriter(consoleOut);
         } else {
@@ -51,7 +51,7 @@
             } catch (LastErrorException e) {
                 if (OSUtils.IS_CONEMU) {
                     if (type == null) {
-                        type = TYPE_WINDOWS_256_COLOR;
+                        type = TYPE_WINDOWS_CONEMU;
                     }
                     writer = new JnaWinConsoleWriter(consoleOut);
                 } else {
@@ -95,6 +95,12 @@
     public Size getSize() {
         Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
         Kernel32.INSTANCE.GetConsoleScreenBufferInfo(consoleOut, info);
+        return new Size(info.windowWidth(), info.windowHeight());
+    }
+
+    public Size getBufferSize() {
+        Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
+        Kernel32.INSTANCE.GetConsoleScreenBufferInfo(consoleOut, info);
         return new Size(info.dwSize.X, info.dwSize.Y);
     }
 
--- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Kernel32.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Kernel32.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl.jna.win;
 
@@ -26,7 +26,7 @@
 interface Kernel32 {//extends StdCallLibrary {
 
     Kernel32 INSTANCE = new Kernel32Impl();
-//    Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
+//    Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
 
 //    Pointer INVALID_HANDLE_VALUE = Pointer.createConstant(-1L);
 
--- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/WindowsAnsiWriter.java	Mon Nov 04 14:26:18 2019 +0800
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/WindowsAnsiWriter.java	Mon Nov 04 09:40:35 2019 +0100
@@ -4,7 +4,7 @@
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
  *
- * http://www.opensource.org/licenses/bsd-license.php
+ * https://opensource.org/licenses/BSD-3-Clause
  */
 package jdk.internal.org.jline.terminal.impl.jna.win;