8214491: Upgrade to JLine 3.9.0
authorjlahoda
Tue, 11 Dec 2018 11:29:28 +0100
changeset 52938 5ff7480c9e28
parent 52937 d2206a60da32
child 52939 9a8585f60c32
8214491: Upgrade to JLine 3.9.0 Summary: Upgrading JLine to 3.9.0 and updating jshell and jjs to the new JLine. Reviewed-by: rfield, sundar
make/CompileJavaModules.gmk
src/jdk.internal.le/share/classes/jdk/internal/jline/DefaultTerminal2.java
src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/OSvTerminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal2.java
src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java
src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java
src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/WCWidth.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AnsiStringsCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java
src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java
src/jdk.internal.le/share/classes/jdk/internal/jline/extra/AnsiInterpretingOutputStream.java
src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Ansi.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Curses.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InfoCmp.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InputStreamReader.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java
src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java
src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java
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/EOFError.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/SyntaxError.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/AnsiWriter.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/ansi.caps
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.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/screen-256color.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/screen.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-256color.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-vtp.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/xterm-256color.caps
src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/xterm.caps
src/jdk.internal.le/share/classes/module-info.java
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/IntByReference.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/Kernel32Impl.java
src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/LastErrorException.java
src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Pointer.java
src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/WindowsAnsiWriter.java
src/jdk.internal.le/windows/classes/module-info.java.extra
src/jdk.internal.le/windows/native/lible/Kernel32.cpp
src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java
src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java
src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java
src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/NashornCompleter.java
test/jdk/jdk/internal/jline/KeyConversionTest.java
test/jdk/jdk/internal/jline/console/StripAnsiTest.java
test/jdk/jdk/internal/jline/extra/AnsiInterpretingOutputStreamTest.java
test/jdk/jdk/internal/jline/extra/HistoryTest.java
test/langtools/jdk/jshell/CommandCompletionTest.java
test/langtools/jdk/jshell/HistoryTest.java
test/langtools/jdk/jshell/HistoryUITest.java
test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java
test/langtools/jdk/jshell/ReplToolTesting.java
test/langtools/jdk/jshell/StartOptionTest.java
test/langtools/jdk/jshell/ToolLocalSimpleTest.java
test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java
test/langtools/jdk/jshell/ToolSimpleTest.java
test/langtools/jdk/jshell/ToolTabCommandTest.java
test/langtools/jdk/jshell/ToolTabSnippetTest.java
test/langtools/jdk/jshell/UITesting.java
test/nashorn/script/nosecurity/JDK-8055034.js.EXPECTED
test/nashorn/script/nosecurity/JDK-8130127.js.EXPECTED
--- a/make/CompileJavaModules.gmk	Tue Dec 11 10:15:28 2018 +0100
+++ b/make/CompileJavaModules.gmk	Tue Dec 11 11:29:28 2018 +0100
@@ -321,7 +321,7 @@
 
 ################################################################################
 
-jdk.internal.le_COPY += .properties
+jdk.internal.le_COPY += .properties .caps .txt
 
 ################################################################################
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/DefaultTerminal2.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import jdk.internal.jline.internal.InfoCmp;
-
-/**
- * Terminal wrapper with default ansi capabilities
- */
-public class DefaultTerminal2 implements Terminal2 {
-
-    private final Terminal terminal;
-    private final Set<String> bools = new HashSet<String>();
-    private final Map<String, String> strings = new HashMap<String, String>();
-
-    public DefaultTerminal2(Terminal terminal) {
-        this.terminal = terminal;
-        registerCap("key_backspace", "^H");
-        registerCap("bell", "^G");
-        registerCap("carriage_return", "^M");
-        if (true/*isSupported() && isAnsiSupported()*/) {
-            registerCap("clr_eol", "\\E[K");
-            registerCap("clr_bol", "\\E[1K");
-            registerCap("cursor_up", "\\E[A");
-            registerCap("cursor_down", "^J");
-            registerCap("column_address", "\\E[%i%p1%dG");
-            registerCap("clear_screen", "\\E[H\\E[2J");
-            registerCap("parm_down_cursor", "\\E[%p1%dB");
-            registerCap("cursor_left", "^H");
-            registerCap("cursor_right", "\\E[C");
-        }
-        if (hasWeirdWrap()) {
-            registerCap("eat_newline_glitch");
-            registerCap("auto_right_margin");
-        }
-    }
-
-    public void init() throws Exception {
-        terminal.init();
-    }
-
-    public void restore() throws Exception {
-        terminal.restore();
-    }
-
-    public void reset() throws Exception {
-        terminal.reset();
-    }
-
-    public boolean isSupported() {
-        return terminal.isSupported();
-    }
-
-    public int getWidth() {
-        return terminal.getWidth();
-    }
-
-    public int getHeight() {
-        return terminal.getHeight();
-    }
-
-    public boolean isAnsiSupported() {
-        return terminal.isAnsiSupported();
-    }
-
-    public OutputStream wrapOutIfNeeded(OutputStream out) {
-        return terminal.wrapOutIfNeeded(out);
-    }
-
-    public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-        return terminal.wrapInIfNeeded(in);
-    }
-
-    public boolean hasWeirdWrap() {
-        return terminal.hasWeirdWrap();
-    }
-
-    public boolean isEchoEnabled() {
-        return terminal.isEchoEnabled();
-    }
-
-    public void setEchoEnabled(boolean enabled) {
-        terminal.setEchoEnabled(enabled);
-    }
-
-    public void disableInterruptCharacter() {
-        terminal.disableInterruptCharacter();
-    }
-
-    public void enableInterruptCharacter() {
-        terminal.enableInterruptCharacter();
-    }
-
-    public String getOutputEncoding() {
-        return terminal.getOutputEncoding();
-    }
-
-    private void registerCap(String cap, String value) {
-        for (String key : InfoCmp.getNames(cap)) {
-            strings.put(key, value);
-        }
-    }
-
-    private void registerCap(String cap) {
-        Collections.addAll(bools, InfoCmp.getNames(cap));
-    }
-
-    public boolean getBooleanCapability(String capability) {
-        return bools.contains(capability);
-    }
-
-    public Integer getNumericCapability(String capability) {
-        return null;
-    }
-
-    public String getStringCapability(String capability) {
-        return strings.get(capability);
-    }
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-// Based on Apache Karaf impl
-
-/**
- * Non-interruptible (via CTRL-C) {@link UnixTerminal}.
- *
- * @since 2.0
- */
-public class NoInterruptUnixTerminal
-    extends UnixTerminal
-{
-    private String intr;
-
-    public NoInterruptUnixTerminal() throws Exception {
-        super();
-    }
-
-    @Override
-    public void init() throws Exception {
-        super.init();
-        intr = getSettings().getPropertyAsString("intr");
-        if ("<undef>".equals(intr)) {
-            intr = null;
-        }
-        if (intr != null) {
-            getSettings().undef("intr");
-        }
-    }
-
-    @Override
-    public void restore() throws Exception {
-        if (intr != null) {
-            getSettings().set("intr", intr);
-        }
-        super.restore();
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/OSvTerminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import jdk.internal.jline.internal.Log;
-
-/**
- * Terminal that is used for OSv. This is seperate to unix terminal
- * implementation because exec cannot be used as currently used by UnixTerminal.
- *
- * This implimentation is derrived from the implementation at
- * https://github.com/cloudius-systems/mgmt/blob/master/crash/src/main/java/com/cloudius/cli/OSvTerminal.java
- * authored by Or Cohen.
- *
- * @author <a href-"mailto:orc@fewbytes.com">Or Cohen</a>
- * @author <a href="mailto:arun.neelicattu@gmail.com">Arun Neelicattu</a>
- * @since 2.13
- */
-public class OSvTerminal
-    extends TerminalSupport
-{
-
-    public Class<?> sttyClass = null;
-    public Object stty = null;
-
-    @SuppressWarnings("deprecation")
-    public OSvTerminal() {
-        super(true);
-
-        setAnsiSupported(true);
-
-        try {
-            if (stty == null) {
-                sttyClass = Class.forName("com.cloudius.util.Stty");
-                stty = sttyClass.newInstance();
-            }
-        } catch (Exception e) {
-            Log.warn("Failed to load com.cloudius.util.Stty", e);
-        }
-    }
-
-    @Override
-    public void init() throws Exception {
-        super.init();
-
-        if (stty != null) {
-            sttyClass.getMethod("jlineMode").invoke(stty);
-        }
-    }
-
-    @Override
-    public void restore() throws Exception {
-        if (stty != null) {
-            sttyClass.getMethod("reset").invoke(stty);
-        }
-        super.restore();
-
-        // Newline in end of restore like in jline.UnixTerminal
-        System.out.println();
-    }
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Representation of the input terminal for a platform.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public interface Terminal
-{
-    void init() throws Exception;
-
-    void restore() throws Exception;
-
-    void reset() throws Exception;
-
-    boolean isSupported();
-
-    int getWidth();
-
-    int getHeight();
-
-    boolean isAnsiSupported();
-
-    /**
-     * When ANSI is not natively handled, the output will have to be wrapped.
-     */
-    OutputStream wrapOutIfNeeded(OutputStream out);
-
-    /**
-     * When using native support, return the InputStream to use for reading characters
-     * else return the input stream passed as a parameter.
-     *
-     * @since 2.6
-     */
-    InputStream wrapInIfNeeded(InputStream in) throws IOException;
-
-    /**
-     * For terminals that don't wrap when character is written in last column,
-     * only when the next character is written.
-     * These are the ones that have 'am' and 'xn' termcap attributes (xterm and
-     * rxvt flavors falls under that category)
-     */
-    boolean hasWeirdWrap();
-
-    boolean isEchoEnabled();
-
-    void setEchoEnabled(boolean enabled);
-
-    void disableInterruptCharacter();
-    void enableInterruptCharacter();
-
-    String getOutputEncoding();
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal2.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-/**
- * Terminal extension.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.13
- */
-public interface Terminal2 extends Terminal
-{
-    boolean getBooleanCapability(String capability);
-
-    Integer getNumericCapability(String capability);
-
-    String getStringCapability(String capability);
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.text.MessageFormat;
-import java.util.HashMap;
-import java.util.Map;
-
-import jdk.internal.jline.internal.Configuration;
-import jdk.internal.jline.internal.Log;
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Creates terminal instances.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class TerminalFactory
-{
-    public static final String JLINE_TERMINAL = "jline.terminal";
-
-    public static final String AUTO = "auto";
-
-    public static final String UNIX = "unix";
-
-    public static final String OSV = "osv";
-
-    public static final String WIN = "win";
-
-    public static final String WINDOWS = "windows";
-
-    public static final String FREEBSD = "freebsd";
-
-    public static final String NONE = "none";
-
-    public static final String OFF = "off";
-
-    public static final String FALSE = "false";
-
-    private static Terminal term = null;
-
-    public static synchronized Terminal create() {
-        return create(null);
-    }
-
-    public static synchronized Terminal create(String ttyDevice) {
-        if (Log.TRACE) {
-            //noinspection ThrowableInstanceNeverThrown
-            Log.trace(new Throwable("CREATE MARKER"));
-        }
-
-        String defaultType = "dumb".equals(System.getenv("TERM")) ? NONE : AUTO;
-        String type  = Configuration.getString(JLINE_TERMINAL, defaultType);
-
-        Log.debug("Creating terminal; type=", type);
-
-        Terminal t;
-        try {
-            String tmp = type.toLowerCase();
-
-            if (tmp.equals(UNIX)) {
-                t = getFlavor(Flavor.UNIX);
-            }
-            else if (tmp.equals(OSV)) {
-                t = getFlavor(Flavor.OSV);
-            }
-            else if (tmp.equals(WIN) || tmp.equals(WINDOWS)) {
-                t = getFlavor(Flavor.WINDOWS);
-            }
-            else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
-                if (System.getenv("INSIDE_EMACS") != null) {
-                    // emacs requires ansi on and echo off
-                    t = new UnsupportedTerminal(true, false);
-                } else  {
-                    // others the other way round
-                    t = new UnsupportedTerminal(false, true);
-                }
-            }
-            else {
-                if (tmp.equals(AUTO)) {
-                    String os = Configuration.getOsName();
-                    Flavor flavor = Flavor.UNIX;
-                    if (os.contains(WINDOWS)) {
-                        flavor = Flavor.WINDOWS;
-                    } else if (System.getenv("OSV_CPUS") != null) {
-                        flavor = Flavor.OSV;
-                    }
-                    t = getFlavor(flavor, ttyDevice);
-                }
-                else {
-                    try {
-                        @SuppressWarnings("deprecation")
-                        Object o = Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
-                        t = (Terminal) o;
-                    }
-                    catch (Exception e) {
-                        throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
-                    }
-                }
-            }
-        }
-        catch (Exception e) {
-            Log.error("Failed to construct terminal; falling back to unsupported", e);
-            t = new UnsupportedTerminal();
-        }
-
-        Log.debug("Created Terminal: ", t);
-
-        try {
-            t.init();
-        }
-        catch (Throwable e) {
-            Log.error("Terminal initialization failed; falling back to unsupported", e);
-            return new UnsupportedTerminal();
-        }
-
-        return t;
-    }
-
-    public static synchronized void reset() {
-        term = null;
-    }
-
-    public static synchronized void resetIf(final Terminal t) {
-        if(t == term) {
-            reset();
-        }
-    }
-
-    public static enum Type
-    {
-        AUTO,
-        WINDOWS,
-        UNIX,
-        OSV,
-        NONE
-    }
-
-    public static synchronized void configure(final String type) {
-        checkNotNull(type);
-        System.setProperty(JLINE_TERMINAL, type);
-    }
-
-    public static synchronized void configure(final Type type) {
-        checkNotNull(type);
-        configure(type.name().toLowerCase());
-    }
-
-    //
-    // Flavor Support
-    //
-
-    public static enum Flavor
-    {
-        WINDOWS,
-        UNIX,
-        OSV
-    }
-
-    private static final Map<Flavor, TerminalConstructor> FLAVORS = new HashMap<>();
-
-    static {
-        registerFlavor(Flavor.WINDOWS, ttyDevice -> new WindowsTerminal());
-        registerFlavor(Flavor.UNIX, ttyDevice -> new UnixTerminal(ttyDevice));
-        registerFlavor(Flavor.OSV, ttyDevice -> new OSvTerminal());
-    }
-
-    public static synchronized Terminal get(String ttyDevice) {
-        // The code is assuming we've got only one terminal per process.
-        // Continuing this assumption, if this terminal is already initialized,
-        // we don't check if it's using the same tty line either. Both assumptions
-        // are a bit crude. TODO: check single terminal assumption.
-        if (term == null) {
-            term = create(ttyDevice);
-        }
-        return term;
-    }
-
-    public static synchronized Terminal get() {
-        return get(null);
-    }
-
-    public static Terminal getFlavor(final Flavor flavor) throws Exception {
-        return getFlavor(flavor, null);
-    }
-
-    @SuppressWarnings("deprecation")
-    public static Terminal getFlavor(final Flavor flavor, String ttyDevice) throws Exception {
-        TerminalConstructor factory = FLAVORS.get(flavor);
-        if (factory != null) {
-            return factory.createTerminal(ttyDevice);
-        } else {
-            throw new InternalError();
-        }
-    }
-
-    public static void registerFlavor(final Flavor flavor, final TerminalConstructor factory) {
-        FLAVORS.put(flavor, factory);
-    }
-
-    public interface TerminalConstructor {
-        public Terminal createTerminal(String str) throws Exception;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import jdk.internal.jline.internal.Log;
-import jdk.internal.jline.internal.ShutdownHooks;
-import jdk.internal.jline.internal.ShutdownHooks.Task;
-
-/**
- * Provides support for {@link Terminal} instances.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public abstract class TerminalSupport
-    implements Terminal
-{
-    public static final int DEFAULT_WIDTH = 80;
-
-    public static final int DEFAULT_HEIGHT = 24;
-
-    private Task shutdownTask;
-
-    private boolean supported;
-
-    private boolean echoEnabled;
-
-    private boolean ansiSupported;
-
-    protected TerminalSupport(final boolean supported) {
-        this.supported = supported;
-    }
-
-    public void init() throws Exception {
-        if (shutdownTask != null) {
-            ShutdownHooks.remove(shutdownTask);
-        }
-        // Register a task to restore the terminal on shutdown
-        this.shutdownTask = ShutdownHooks.add(new Task()
-        {
-            public void run() throws Exception {
-                restore();
-            }
-        });
-    }
-
-    public void restore() throws Exception {
-        TerminalFactory.resetIf(this);
-        if (shutdownTask != null) {
-          ShutdownHooks.remove(shutdownTask);
-          shutdownTask = null;
-        }
-    }
-
-    public void reset() throws Exception {
-        restore();
-        init();
-    }
-
-    public final boolean isSupported() {
-        return supported;
-    }
-
-    public synchronized boolean isAnsiSupported() {
-        return ansiSupported;
-    }
-
-    protected synchronized void setAnsiSupported(final boolean supported) {
-        this.ansiSupported = supported;
-        Log.debug("Ansi supported: ", supported);
-    }
-
-    /**
-     * Subclass to change behavior if needed.
-     * @return the passed out
-     */
-    public OutputStream wrapOutIfNeeded(OutputStream out) {
-        return out;
-    }
-
-    /**
-     * Defaults to true which was the behaviour before this method was added.
-     */
-    public boolean hasWeirdWrap() {
-        return true;
-    }
-
-    public int getWidth() {
-        return DEFAULT_WIDTH;
-    }
-
-    public int getHeight() {
-        return DEFAULT_HEIGHT;
-    }
-
-    public synchronized boolean isEchoEnabled() {
-        return echoEnabled;
-    }
-
-    public synchronized void setEchoEnabled(final boolean enabled) {
-        this.echoEnabled = enabled;
-        Log.debug("Echo enabled: ", enabled);
-    }
-
-    public void disableInterruptCharacter() {
-    }
-
-    public void enableInterruptCharacter() {
-    }
-
-    public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-        return in;
-    }
-
-    public String getOutputEncoding() {
-        // null for unknown
-        return null;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import jdk.internal.jline.internal.Configuration;
-import jdk.internal.jline.internal.InfoCmp;
-import jdk.internal.jline.internal.Log;
-import jdk.internal.jline.internal.TerminalLineSettings;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Terminal that is used for unix platforms. Terminal initialization
- * is handled by issuing the <em>stty</em> command against the
- * <em>/dev/tty</em> file to disable character echoing and enable
- * character input. All known unix systems (including
- * Linux and Macintosh OS X) support the <em>stty</em>), so this
- * implementation should work for an reasonable POSIX system.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
- * @since 2.0
- */
-public class UnixTerminal
-    extends TerminalSupport
-    implements Terminal2
-{
-    private final TerminalLineSettings settings;
-    private final String type;
-    private String intr;
-    private String lnext;
-    private Set<String> bools = new HashSet<String>();
-    private Map<String, Integer> ints = new HashMap<String, Integer>();
-    private Map<String, String> strings = new HashMap<String, String>();
-
-    public UnixTerminal() throws Exception {
-        this(TerminalLineSettings.DEFAULT_TTY, null);
-    }
-
-    public UnixTerminal(String ttyDevice) throws Exception {
-        this(ttyDevice, null);
-    }
-
-    public UnixTerminal(String ttyDevice, String type) throws Exception {
-        super(true);
-        checkNotNull(ttyDevice);
-        this.settings = TerminalLineSettings.getSettings(ttyDevice);
-        if (type == null) {
-            type = System.getenv("TERM");
-        }
-        this.type = type;
-        parseInfoCmp();
-    }
-
-    public TerminalLineSettings getSettings() {
-        return settings;
-    }
-
-    /**
-     * Remove line-buffered input by invoking "stty -icanon min 1"
-     * against the current terminal.
-     */
-    @Override
-    public void init() throws Exception {
-        super.init();
-
-        setAnsiSupported(true);
-
-        // Set the console to be character-buffered instead of line-buffered.
-        // Make sure we're distinguishing carriage return from newline.
-        // Allow ctrl-s keypress to be used (as forward search)
-        //
-        // Please note that FreeBSD does not seem to support -icrnl and thus
-        // has to be handled separately. Otherwise the console will be "stuck"
-        // and will neither accept input nor print anything to stdout.
-        if (Configuration.getOsName().contains(TerminalFactory.FREEBSD)) {
-            settings.set("-icanon min 1 -inlcr -ixon");
-        } else {
-            settings.set("-icanon min 1 -icrnl -inlcr -ixon");
-        }
-        settings.undef("dsusp");
-
-        setEchoEnabled(false);
-
-        parseInfoCmp();
-    }
-
-    /**
-     * Restore the original terminal configuration, which can be used when
-     * shutting down the console reader. The ConsoleReader cannot be
-     * used after calling this method.
-     */
-    @Override
-    public void restore() throws Exception {
-        settings.restore();
-        super.restore();
-    }
-
-    /**
-     * Returns the value of <tt>stty columns</tt> param.
-     */
-    @Override
-    public int getWidth() {
-        int w = settings.getProperty("columns");
-        return w < 1 ? DEFAULT_WIDTH : w;
-    }
-
-    /**
-     * Returns the value of <tt>stty rows>/tt> param.
-     */
-    @Override
-    public int getHeight() {
-        int h = settings.getProperty("rows");
-        return h < 1 ? DEFAULT_HEIGHT : h;
-    }
-
-    @Override
-    public boolean hasWeirdWrap() {
-        return getBooleanCapability("auto_right_margin")
-                && getBooleanCapability("eat_newline_glitch");
-    }
-
-    @Override
-    public synchronized void setEchoEnabled(final boolean enabled) {
-        try {
-            if (enabled) {
-                settings.set("echo");
-            }
-            else {
-                settings.set("-echo");
-            }
-            super.setEchoEnabled(enabled);
-        }
-        catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.error("Failed to ", enabled ? "enable" : "disable", " echo", e);
-        }
-    }
-
-    public void disableInterruptCharacter()
-    {
-        try {
-            intr = getSettings().getPropertyAsString("intr");
-            if ("<undef>".equals(intr)) {
-                intr = null;
-            }
-            settings.undef("intr");
-        }
-        catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.error("Failed to disable interrupt character", e);
-        }
-    }
-
-    public void enableInterruptCharacter()
-    {
-        try {
-            if (intr != null) {
-                settings.set("intr", intr);
-            }
-        }
-        catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.error("Failed to enable interrupt character", e);
-        }
-    }
-
-    public void disableLitteralNextCharacter()
-    {
-        try {
-            lnext = getSettings().getPropertyAsString("lnext");
-            if ("<undef>".equals(lnext)) {
-                lnext = null;
-            }
-            settings.undef("lnext");
-        }
-        catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.error("Failed to disable litteral next character", e);
-        }
-    }
-
-    public void enableLitteralNextCharacter()
-    {
-        try {
-            if (lnext != null) {
-                settings.set("lnext", lnext);
-            }
-        }
-        catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.error("Failed to enable litteral next character", e);
-        }
-    }
-
-    public boolean getBooleanCapability(String capability) {
-        return bools.contains(capability);
-    }
-
-    public Integer getNumericCapability(String capability) {
-        return ints.get(capability);
-    }
-
-    public String getStringCapability(String capability) {
-        return strings.get(capability);
-    }
-
-    private void parseInfoCmp() {
-        String capabilities = null;
-        if (type != null) {
-            try {
-                capabilities = InfoCmp.getInfoCmp(type);
-            } catch (Exception e) {
-            }
-        }
-        if (capabilities == null) {
-            capabilities = InfoCmp.getAnsiCaps();
-        }
-        InfoCmp.parseInfoCmp(capabilities, bools, ints, strings);
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-/**
- * An unsupported terminal.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class UnsupportedTerminal
-    extends TerminalSupport
-{
-    public UnsupportedTerminal() {
-        this(false, true);
-    }
-
-    public UnsupportedTerminal(boolean ansiSupported, boolean echoEnabled) {
-        super(false);
-        setAnsiSupported(ansiSupported);
-        setEchoEnabled(echoEnabled);
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream;
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream.BufferState;
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream.Performer;
-import jdk.internal.jline.internal.Configuration;
-import jdk.internal.jline.internal.Log;
-//import org.fusesource.jansi.internal.WindowsSupport;
-//import org.fusesource.jansi.internal.Kernel32;
-//import static org.fusesource.jansi.internal.Kernel32.*;
-
-import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
-import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
-import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
-import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;
-
-/**
- * Terminal implementation for Microsoft Windows. Terminal initialization in
- * {@link #init} is accomplished by extracting the
- * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
- * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
- * property), loading the library, and then calling the Win32 APIs <a
- * href="http://msdn.microsoft.com/library/default.asp?
- * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
- * <a href="http://msdn.microsoft.com/library/default.asp?
- * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
- * disable character echoing.
- * <p/>
- * <p>
- * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
- * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
- * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
- * directly invoke the readc() method in the JNI library. This is so the class
- * can read special keys (like arrow keys) which are otherwise inaccessible via
- * the {@link System#in} stream. Using JNI reading can be bypassed by setting
- * the <code>jline.WindowsTerminal.directConsole</code> system property
- * to <code>false</code>.
- * </p>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class WindowsTerminal
-    extends TerminalSupport
-{
-    public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
-
-    public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
-
-    private boolean directConsole;
-
-    private int originalMode;
-
-    public WindowsTerminal() throws Exception {
-        super(true);
-    }
-
-    @Override
-    public void init() throws Exception {
-        super.init();
-
-//        setAnsiSupported(Configuration.getBoolean(ANSI, true));
-        setAnsiSupported(true);
-
-        //
-        // FIXME: Need a way to disable direct console and sysin detection muck
-        //
-
-        setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
-
-        this.originalMode = getConsoleMode();
-        setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
-        setEchoEnabled(false);
-    }
-
-    /**
-     * Restore the original terminal configuration, which can be used when
-     * shutting down the console reader. The ConsoleReader cannot be
-     * used after calling this method.
-     */
-    @Override
-    public void restore() throws Exception {
-        // restore the old console mode
-        setConsoleMode(originalMode);
-        super.restore();
-    }
-
-    @Override
-    public int getWidth() {
-        int w = getWindowsTerminalWidth();
-        return w < 1 ? DEFAULT_WIDTH : w;
-    }
-
-    @Override
-    public int getHeight() {
-        int h = getWindowsTerminalHeight();
-        return h < 1 ? DEFAULT_HEIGHT : h;
-    }
-
-    @Override
-    public void setEchoEnabled(final boolean enabled) {
-        // Must set these four modes at the same time to make it work fine.
-        if (enabled) {
-            setConsoleMode(getConsoleMode() |
-                ENABLE_ECHO_INPUT.code |
-                ENABLE_LINE_INPUT.code |
-                ENABLE_WINDOW_INPUT.code);
-        }
-        else {
-            setConsoleMode(getConsoleMode() &
-                ~(ENABLE_LINE_INPUT.code |
-                    ENABLE_ECHO_INPUT.code |
-                    ENABLE_WINDOW_INPUT.code));
-        }
-        super.setEchoEnabled(enabled);
-    }
-
-    public void disableInterruptCharacter() {
-        setConsoleMode(getConsoleMode() &
-            ~(ENABLE_PROCESSED_INPUT.code));
-    }
-
-    public void enableInterruptCharacter() {
-        setConsoleMode(getConsoleMode() |
-            ENABLE_PROCESSED_INPUT.code);
-    }
-
-    /**
-     * Whether or not to allow the use of the JNI console interaction.
-     */
-    public void setDirectConsole(final boolean flag) {
-        this.directConsole = flag;
-        Log.debug("Direct console: ", flag);
-    }
-
-    /**
-     * Whether or not to allow the use of the JNI console interaction.
-     */
-    public Boolean getDirectConsole() {
-        return directConsole;
-    }
-
-
-    @Override
-    public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-        if (directConsole && isSystemIn(in)) {
-            return new InputStream() {
-                private byte[] buf = null;
-                int bufIdx = 0;
-
-                @Override
-                public int read() throws IOException {
-                    while (buf == null || bufIdx == buf.length) {
-                        buf = readConsoleInput();
-                        bufIdx = 0;
-                    }
-                    int c = buf[bufIdx] & 0xFF;
-                    bufIdx++;
-                    return c;
-                }
-            };
-        } else {
-            return super.wrapInIfNeeded(in);
-        }
-    }
-
-    protected boolean isSystemIn(final InputStream in) throws IOException {
-        if (in == null) {
-            return false;
-        }
-        else if (in == System.in) {
-            return true;
-        }
-        else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
-            return true;
-        }
-
-        return false;
-    }
-
-    @Override
-    public OutputStream wrapOutIfNeeded(OutputStream out) {
-        return new AnsiInterpretingOutputStream(getOutputEncoding(), out, new Performer() {
-            @Override
-            public BufferState getBufferState() throws IOException {
-                out.flush();
-                return WindowsTerminal.this.getBufferState();
-            }
-            @Override
-            public void setCursorPosition(int cursorX, int cursorY) throws IOException {
-                out.flush();
-                WindowsTerminal.this.setCursorPosition(cursorX, cursorY);
-            }
-        });
-    }
-
-    @Override
-    public String getOutputEncoding() {
-        int codepage = getConsoleOutputCodepage();
-        //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
-        String charsetMS = "ms" + codepage;
-        if (java.nio.charset.Charset.isSupported(charsetMS)) {
-            return charsetMS;
-        }
-        String charsetCP = "cp" + codepage;
-        if (java.nio.charset.Charset.isSupported(charsetCP)) {
-            return charsetCP;
-        }
-        Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
-        return super.getOutputEncoding();
-    }
-
-    //
-    // Original code:
-    //
-//    private int getConsoleMode() {
-//        return WindowsSupport.getConsoleMode();
-//    }
-//
-//    private void setConsoleMode(int mode) {
-//        WindowsSupport.setConsoleMode(mode);
-//    }
-//
-//    private byte[] readConsoleInput() {
-//        // XXX does how many events to read in one call matter?
-//        INPUT_RECORD[] events = null;
-//        try {
-//            events = WindowsSupport.readConsoleInput(1);
-//        } catch (IOException e) {
-//            Log.debug("read Windows console input error: ", e);
-//        }
-//        if (events == null) {
-//            return new byte[0];
-//        }
-//        StringBuilder sb = new StringBuilder();
-//        for (int i = 0; i < events.length; i++ ) {
-//            KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
-//            //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
-//            if (keyEvent.keyDown) {
-//                if (keyEvent.uchar > 0) {
-//                    // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
-//                    // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
-//                    final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
-//                    // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
-//                    // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
-//                    final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;
-//                    if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
-//                        && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
-//                        sb.append('\u001B'); // ESC
-//                    }
-//
-//                    sb.append(keyEvent.uchar);
-//                    continue;
-//                }
-//                // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
-//                // just add support for basic editing keys (no control state, no numpad keys)
-//                String escapeSequence = null;
-//                switch (keyEvent.keyCode) {
-//                case 0x21: // VK_PRIOR PageUp
-//                    escapeSequence = "\u001B[5~";
-//                    break;
-//                case 0x22: // VK_NEXT PageDown
-//                    escapeSequence = "\u001B[6~";
-//                    break;
-//                case 0x23: // VK_END
-//                    escapeSequence = "\u001B[4~";
-//                    break;
-//                case 0x24: // VK_HOME
-//                    escapeSequence = "\u001B[1~";
-//                    break;
-//                case 0x25: // VK_LEFT
-//                    escapeSequence = "\u001B[D";
-//                    break;
-//                case 0x26: // VK_UP
-//                    escapeSequence = "\u001B[A";
-//                    break;
-//                case 0x27: // VK_RIGHT
-//                    escapeSequence = "\u001B[C";
-//                    break;
-//                case 0x28: // VK_DOWN
-//                    escapeSequence = "\u001B[B";
-//                    break;
-//                case 0x2D: // VK_INSERT
-//                    escapeSequence = "\u001B[2~";
-//                    break;
-//                case 0x2E: // VK_DELETE
-//                    escapeSequence = "\u001B[3~";
-//                    break;
-//                default:
-//                    break;
-//                }
-//                if (escapeSequence != null) {
-//                    for (int k = 0; k < keyEvent.repeatCount; k++) {
-//                        sb.append(escapeSequence);
-//                    }
-//                }
-//            } else {
-//                // key up event
-//                // support ALT+NumPad input method
-//                if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
-//                    sb.append(keyEvent.uchar);
-//                }
-//            }
-//        }
-//        return sb.toString().getBytes();
-//    }
-//
-//    private int getConsoleOutputCodepage() {
-//        return Kernel32.GetConsoleOutputCP();
-//    }
-//
-//    private int getWindowsTerminalWidth() {
-//        return WindowsSupport.getWindowsTerminalWidth();
-//    }
-//
-//    private int getWindowsTerminalHeight() {
-//        return WindowsSupport.getWindowsTerminalHeight();
-//    }
-
-    //
-    // Native Bits
-    //
-    static {
-        System.loadLibrary("le");
-        initIDs();
-    }
-
-    private static native void initIDs();
-
-    protected native int getConsoleMode();
-
-    protected native void setConsoleMode(int mode);
-
-    private byte[] readConsoleInput() {
-        KEY_EVENT_RECORD keyEvent = readKeyEvent();
-
-        return convertKeys(keyEvent).getBytes();
-    }
-
-    public static String convertKeys(KEY_EVENT_RECORD keyEvent) {
-        if (keyEvent == null) {
-            return "";
-        }
-
-        StringBuilder sb = new StringBuilder();
-
-        if (keyEvent.keyDown) {
-            if (keyEvent.uchar > 0) {
-                // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
-                // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
-                final int altState = KEY_EVENT_RECORD.ALT_PRESSED;
-                // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
-                // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
-                final int ctrlState = KEY_EVENT_RECORD.CTRL_PRESSED;
-
-                boolean handled = false;
-
-                if ((keyEvent.controlKeyState & ctrlState) != 0) {
-                    switch (keyEvent.keyCode) {
-                        case 0x43: //Ctrl-C
-                            sb.append("\003");
-                            handled = true;
-                            break;
-                    }
-                }
-
-                if ((keyEvent.controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
-                    switch (keyEvent.keyCode) {
-                        case 0x09: //Shift-Tab
-                            sb.append("\033\133\132");
-                            handled = true;
-                            break;
-                    }
-                }
-
-                if (!handled) {
-                    if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
-                        && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
-                        sb.append('\u001B'); // ESC
-                    }
-
-                    sb.append(keyEvent.uchar);
-                }
-            } else {
-                // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
-                // xterm escape codes: E. Moy, S. Gildea and T. Dickey, "XTerm Control Sequences":
-                // http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
-                // http://xorg.freedesktop.org/releases/X11R6.8.1/PDF/ctlseqs.pdf
-                // just add support for basic editing keys and function keys
-                String escapeSequence = null;
-                switch (keyEvent.keyCode) {
-                case 0x21: // VK_PRIOR PageUp
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[5~", "\u001B[5;%d~");
-                    break;
-                case 0x22: // VK_NEXT PageDown
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[6~", "\u001B[6;%d~");
-                    break;
-                case 0x23: // VK_END
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[4~", "\u001B[4;%d~");
-                    break;
-                case 0x24: // VK_HOME
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[1~", "\u001B[1;%d~");
-                    break;
-                case 0x25: // VK_LEFT
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[D", "\u001B[1;%dD");
-                    break;
-                case 0x26: // VK_UP
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[A", "\u001B[1;%dA");
-                    break;
-                case 0x27: // VK_RIGHT
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[C", "\u001B[1;%dC");
-                    break;
-                case 0x28: // VK_DOWN
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[B", "\u001B[1;%dB");
-                    break;
-                case 0x2D: // VK_INSERT
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[2~", "\u001B[2;%d~");
-                    break;
-                case 0x2E: // VK_DELETE
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
-                    break;
-                case 0x70: // VK_F1
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOP", "\u001BO%dP");
-                    break;
-                case 0x71: // VK_F2
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOQ", "\u001BO%dQ");
-                    break;
-                case 0x72: // VK_F3
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOR", "\u001BO%dR");
-                    break;
-                case 0x73: // VK_F4
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOS", "\u001BO%dS");
-                    break;
-                case 0x74: // VK_F5
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[15~", "\u001B[15;%d~");
-                    break;
-                case 0x75: // VK_F6
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[17~", "\u001B[17;%d~");
-                    break;
-                case 0x76: // VK_F7
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[18~", "\u001B[18;%d~");
-                    break;
-                case 0x77: // VK_F8
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[19~", "\u001B[19;%d~");
-                    break;
-                case 0x78: // VK_F9
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[20~", "\u001B[20;%d~");
-                    break;
-                case 0x79: // VK_F10
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[21~", "\u001B[21;%d~");
-                    break;
-                case 0x7A: // VK_F11
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[23~", "\u001B[23;%d~");
-                    break;
-                case 0x7B: // VK_F12
-                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[24~", "\u001B[24;%d~");
-                    break;
-                default:
-                    break;
-                }
-                if (escapeSequence != null) {
-                    for (int k = 0; k < keyEvent.repeatCount; k++) {
-                        sb.append(escapeSequence);
-                    }
-                }
-            }
-        } else {
-            // key up event
-            // support ALT+NumPad input method
-            if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
-                sb.append(keyEvent.uchar);
-            }
-        }
-        return sb.toString();
-    }
-
-    private static String escapeSequence(int controlKeyState, String noControlSequence, String withControlSequence) {
-        int controlNum = 1;
-
-        if ((controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
-            controlNum += 1;
-        }
-
-        if ((controlKeyState & KEY_EVENT_RECORD.ALT_PRESSED) != 0) {
-            controlNum += 2;
-        }
-
-        if ((controlKeyState & KEY_EVENT_RECORD.CTRL_PRESSED) != 0) {
-            controlNum += 4;
-        }
-
-        if (controlNum > 1) {
-            return String.format(withControlSequence, controlNum);
-        } else {
-            return noControlSequence;
-        }
-    }
-
-    private native KEY_EVENT_RECORD readKeyEvent();
-
-    public static class KEY_EVENT_RECORD {
-        public final static int ALT_PRESSED = 0x3;
-        public final static int CTRL_PRESSED = 0xC;
-        public final static int SHIFT_PRESSED = 0x10;
-        public final boolean keyDown;
-        public final char uchar;
-        public final int controlKeyState;
-        public final int keyCode;
-        public final int repeatCount;
-
-        public KEY_EVENT_RECORD(boolean keyDown, char uchar, int controlKeyState, int keyCode, int repeatCount) {
-            this.keyDown = keyDown;
-            this.uchar = uchar;
-            this.controlKeyState = controlKeyState;
-            this.keyCode = keyCode;
-            this.repeatCount = repeatCount;
-        }
-
-    }
-
-    private native int getConsoleOutputCodepage();
-
-    private native int getWindowsTerminalWidth();
-
-    private native int getWindowsTerminalHeight();
-
-    private native BufferState getBufferState();
-
-    private native void setCursorPosition(int x, int y);
-
-    /**
-     * Console mode
-     * <p/>
-     * Constants copied <tt>wincon.h</tt>.
-     */
-    public static enum ConsoleMode
-    {
-        /**
-         * The ReadFile or ReadConsole function returns only when a carriage return
-         * character is read. If this mode is disable, the functions return when one
-         * or more characters are available.
-         */
-        ENABLE_LINE_INPUT(2),
-
-        /**
-         * Characters read by the ReadFile or ReadConsole function are written to
-         * the active screen buffer as they are read. This mode can be used only if
-         * the ENABLE_LINE_INPUT mode is also enabled.
-         */
-        ENABLE_ECHO_INPUT(4),
-
-        /**
-         * CTRL+C is processed by the system and is not placed in the input buffer.
-         * If the input buffer is being read by ReadFile or ReadConsole, other
-         * control keys are processed by the system and are not returned in the
-         * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
-         * enabled, backspace, carriage return, and linefeed characters are handled
-         * by the system.
-         */
-        ENABLE_PROCESSED_INPUT(1),
-
-        /**
-         * User interactions that change the size of the console screen buffer are
-         * reported in the console's input buffee. Information about these events
-         * can be read from the input buffer by applications using
-         * theReadConsoleInput function, but not by those using ReadFile
-         * orReadConsole.
-         */
-        ENABLE_WINDOW_INPUT(8),
-
-        /**
-         * If the mouse pointer is within the borders of the console window and the
-         * window has the keyboard focus, mouse events generated by mouse movement
-         * and button presses are placed in the input buffer. These events are
-         * discarded by ReadFile or ReadConsole, even when this mode is enabled.
-         */
-        ENABLE_MOUSE_INPUT(16),
-
-        /**
-         * When enabled, text entered in a console window will be inserted at the
-         * current cursor location and all text following that location will not be
-         * overwritten. When disabled, all following text will be overwritten. An OR
-         * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
-         * flag to enable this functionality.
-         */
-        ENABLE_PROCESSED_OUTPUT(1),
-
-        /**
-         * This flag enables the user to use the mouse to select and edit text. To
-         * enable this option, use the OR to combine this flag with
-         * ENABLE_EXTENDED_FLAGS.
-         */
-        ENABLE_WRAP_AT_EOL_OUTPUT(2),;
-
-        public final int code;
-
-        ConsoleMode(final int code) {
-            this.code = code;
-        }
-    }
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,387 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import jdk.internal.jline.internal.Log;
-
-/**
- * @author St\u00E5le W. Pedersen <stale.pedersen@jboss.org>
- */
-public class ConsoleKeys {
-
-    private KeyMap keys;
-
-    private Map<String, KeyMap> keyMaps;
-    private Map<String, String> variables = new HashMap<String,String>();
-
-    public ConsoleKeys(String appName, URL inputrcUrl) {
-        keyMaps = KeyMap.keyMaps();
-        setVar("editing-mode", "emacs");
-        loadKeys(appName, inputrcUrl);
-        String editingMode = variables.get("editing-mode");
-        if ("vi".equalsIgnoreCase(editingMode)) {
-            keys = keyMaps.get(KeyMap.VI_INSERT);
-        } else if ("emacs".equalsIgnoreCase(editingMode)) {
-            keys = keyMaps.get(KeyMap.EMACS);
-        }
-    }
-
-    protected boolean setKeyMap (String name) {
-        KeyMap map = keyMaps.get(name);
-        if (map == null) {
-            return false;
-        }
-        this.keys = map;
-        return true;
-    }
-
-    protected Map<String, KeyMap> getKeyMaps() {
-        return keyMaps;
-    }
-
-    protected KeyMap getKeys() {
-        return keys;
-    }
-
-    protected void setKeys(KeyMap keys) {
-        this.keys = keys;
-    }
-
-    protected void loadKeys(String appName, URL inputrcUrl) {
-        keys = keyMaps.get(KeyMap.EMACS);
-
-        try {
-            InputStream input = inputrcUrl.openStream();
-            try {
-                loadKeys(input, appName);
-                Log.debug("Loaded user configuration: ", inputrcUrl);
-            }
-            finally {
-                try {
-                    input.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
-        }
-        catch (IOException e) {
-            if (inputrcUrl.getProtocol().equals("file")) {
-                File file = new File(inputrcUrl.getPath());
-                if (file.exists()) {
-                    Log.warn("Unable to read user configuration: ", inputrcUrl, e);
-                }
-            } else {
-                Log.warn("Unable to read user configuration: ", inputrcUrl, e);
-            }
-        }
-    }
-
-    private void loadKeys(InputStream input, String appName) throws IOException {
-        BufferedReader reader = new BufferedReader( new java.io.InputStreamReader( input ) );
-        String line;
-        boolean parsing = true;
-        List<Boolean> ifsStack = new ArrayList<Boolean>();
-        while ( (line = reader.readLine()) != null ) {
-            try {
-                line = line.trim();
-                if (line.length() == 0) {
-                    continue;
-                }
-                if (line.charAt(0) == '#') {
-                    continue;
-                }
-                int i = 0;
-                if (line.charAt(i) == '$') {
-                    String cmd;
-                    String args;
-                    for (++i; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
-                    int s = i;
-                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
-                    cmd = line.substring(s, i);
-                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
-                    s = i;
-                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
-                    args = line.substring(s, i);
-                    if ("if".equalsIgnoreCase(cmd)) {
-                        ifsStack.add( parsing );
-                        if (!parsing) {
-                            continue;
-                        }
-                        if (args.startsWith("term=")) {
-                            // TODO
-                        } else if (args.startsWith("mode=")) {
-                            String mode = variables.get("editing-mode");
-                            parsing = args.substring("mode=".length()).equalsIgnoreCase(mode);
-                        } else {
-                            parsing = args.equalsIgnoreCase(appName);
-                        }
-                    } else if ("else".equalsIgnoreCase(cmd)) {
-                        if (ifsStack.isEmpty()) {
-                            throw new IllegalArgumentException("$else found without matching $if");
-                        }
-                        boolean invert = true;
-                        for (boolean b : ifsStack) {
-                            if (!b) {
-                                invert = false;
-                                break;
-                            }
-                        }
-                        if (invert) {
-                            parsing = !parsing;
-                        }
-                    } else if ("endif".equalsIgnoreCase(cmd)) {
-                        if (ifsStack.isEmpty()) {
-                            throw new IllegalArgumentException("endif found without matching $if");
-                        }
-                        parsing = ifsStack.remove( ifsStack.size() - 1 );
-                    } else if ("include".equalsIgnoreCase(cmd)) {
-                        // TODO
-                    }
-                    continue;
-                }
-                if (!parsing) {
-                    continue;
-                }
-                boolean equivalency;
-                String keySeq = "";
-                if (line.charAt(i++) == '"') {
-                    boolean esc = false;
-                    for (;; i++) {
-                        if (i >= line.length()) {
-                            throw new IllegalArgumentException("Missing closing quote on line '" + line + "'");
-                        }
-                        if (esc) {
-                            esc = false;
-                        } else if (line.charAt(i) == '\\') {
-                            esc = true;
-                        } else if (line.charAt(i) == '"') {
-                            break;
-                        }
-                    }
-                }
-                for (; i < line.length() && line.charAt(i) != ':'
-                        && line.charAt(i) != ' ' && line.charAt(i) != '\t'
-                        ; i++);
-                keySeq = line.substring(0, i);
-                equivalency = i + 1 < line.length() && line.charAt(i) == ':' && line.charAt(i + 1) == '=';
-                i++;
-                if (equivalency) {
-                    i++;
-                }
-                if (keySeq.equalsIgnoreCase("set")) {
-                    String key;
-                    String val;
-                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
-                    int s = i;
-                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
-                    key = line.substring( s, i );
-                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
-                    s = i;
-                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
-                    val = line.substring( s, i );
-                    setVar( key, val );
-                } else {
-                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
-                    int start = i;
-                    if (i < line.length() && (line.charAt(i) == '\'' || line.charAt(i) == '\"')) {
-                        char delim = line.charAt(i++);
-                        boolean esc = false;
-                        for (;; i++) {
-                            if (i >= line.length()) {
-                                break;
-                            }
-                            if (esc) {
-                                esc = false;
-                            } else if (line.charAt(i) == '\\') {
-                                esc = true;
-                            } else if (line.charAt(i) == delim) {
-                                break;
-                            }
-                        }
-                    }
-                    for (; i < line.length() && line.charAt(i) != ' ' && line.charAt(i) != '\t'; i++);
-                    String val = line.substring(Math.min(start, line.length()), Math.min(i, line.length()));
-                    if (keySeq.charAt(0) == '"') {
-                        keySeq = translateQuoted(keySeq);
-                    } else {
-                        // Bind key name
-                        String keyName = keySeq.lastIndexOf('-') > 0 ? keySeq.substring( keySeq.lastIndexOf('-') + 1 ) : keySeq;
-                        char key = getKeyFromName(keyName);
-                        keyName = keySeq.toLowerCase();
-                        keySeq = "";
-                        if (keyName.contains("meta-") || keyName.contains("m-")) {
-                            keySeq += "\u001b";
-                        }
-                        if (keyName.contains("control-") || keyName.contains("c-") || keyName.contains("ctrl-")) {
-                            key = (char)(Character.toUpperCase( key ) & 0x1f);
-                        }
-                        keySeq += key;
-                    }
-                    if (val.length() > 0 && (val.charAt(0) == '\'' || val.charAt(0) == '\"')) {
-                        keys.bind( keySeq, translateQuoted(val) );
-                    } else {
-                        String operationName = val.replace('-', '_').toUpperCase();
-                        try {
-                          keys.bind(keySeq, Operation.valueOf(operationName));
-                        } catch(IllegalArgumentException e) {
-                          Log.info("Unable to bind key for unsupported operation: ", val);
-                        }
-                    }
-                }
-            } catch (IllegalArgumentException e) {
-              Log.warn("Unable to parse user configuration: ", e);
-            }
-        }
-    }
-
-    private static String translateQuoted(String keySeq) {
-        int i;
-        String str = keySeq.substring( 1, keySeq.length() - 1 );
-        keySeq = "";
-        for (i = 0; i < str.length(); i++) {
-            char c = str.charAt(i);
-            if (c == '\\') {
-                boolean ctrl = str.regionMatches(i, "\\C-", 0, 3)|| str.regionMatches(i, "\\M-\\C-", 0, 6);
-                boolean meta = str.regionMatches(i, "\\M-", 0, 3)|| str.regionMatches(i, "\\C-\\M-", 0, 6);
-                i += (meta ? 3 : 0) + (ctrl ? 3 : 0) + (!meta && !ctrl ? 1 : 0);
-                if (i >= str.length()) {
-                    break;
-                }
-                c = str.charAt(i);
-                if (meta) {
-                    keySeq += "\u001b";
-                }
-                if (ctrl) {
-                    c = c == '?' ? 0x7f : (char)(Character.toUpperCase( c ) & 0x1f);
-                }
-                if (!meta && !ctrl) {
-                    switch (c) {
-                        case 'a': c = 0x07; break;
-                        case 'b': c = '\b'; break;
-                        case 'd': c = 0x7f; break;
-                        case 'e': c = 0x1b; break;
-                        case 'f': c = '\f'; break;
-                        case 'n': c = '\n'; break;
-                        case 'r': c = '\r'; break;
-                        case 't': c = '\t'; break;
-                        case 'v': c = 0x0b; break;
-                        case '\\': c = '\\'; break;
-                        case '0': case '1': case '2': case '3':
-                        case '4': case '5': case '6': case '7':
-                            c = 0;
-                            for (int j = 0; j < 3; j++, i++) {
-                                if (i >= str.length()) {
-                                    break;
-                                }
-                                int k = Character.digit(str.charAt(i), 8);
-                                if (k < 0) {
-                                    break;
-                                }
-                                c = (char)(c * 8 + k);
-                            }
-                            c &= 0xFF;
-                            break;
-                        case 'x':
-                            i++;
-                            c = 0;
-                            for (int j = 0; j < 2; j++, i++) {
-                                if (i >= str.length()) {
-                                    break;
-                                }
-                                int k = Character.digit(str.charAt(i), 16);
-                                if (k < 0) {
-                                    break;
-                                }
-                                c = (char)(c * 16 + k);
-                            }
-                            c &= 0xFF;
-                            break;
-                        case 'u':
-                            i++;
-                            c = 0;
-                            for (int j = 0; j < 4; j++, i++) {
-                                if (i >= str.length()) {
-                                    break;
-                                }
-                                int k = Character.digit(str.charAt(i), 16);
-                                if (k < 0) {
-                                    break;
-                                }
-                                c = (char)(c * 16 + k);
-                            }
-                            break;
-                    }
-                }
-                keySeq += c;
-            } else {
-                keySeq += c;
-            }
-        }
-        return keySeq;
-    }
-
-    private static char getKeyFromName(String name) {
-        if ("DEL".equalsIgnoreCase(name) || "Rubout".equalsIgnoreCase(name)) {
-            return 0x7f;
-        } else if ("ESC".equalsIgnoreCase(name) || "Escape".equalsIgnoreCase(name)) {
-            return '\033';
-        } else if ("LFD".equalsIgnoreCase(name) || "NewLine".equalsIgnoreCase(name)) {
-            return '\n';
-        } else if ("RET".equalsIgnoreCase(name) || "Return".equalsIgnoreCase(name)) {
-            return '\r';
-        } else if ("SPC".equalsIgnoreCase(name) || "Space".equalsIgnoreCase(name)) {
-            return ' ';
-        } else if ("Tab".equalsIgnoreCase(name)) {
-            return '\t';
-        } else {
-            return name.charAt(0);
-        }
-    }
-
-    private void setVar(String key, String val) {
-        if ("keymap".equalsIgnoreCase(key)) {
-            if (keyMaps.containsKey(val)) {
-                keys = keyMaps.get(val);
-            }
-        } else if ("blink-matching-paren".equals(key)) {
-            if ("on".equalsIgnoreCase(val)) {
-              keys.setBlinkMatchingParen(true);
-            } else if ("off".equalsIgnoreCase(val)) {
-              keys.setBlinkMatchingParen(false);
-            }
-        }
-
-        /*
-         * Technically variables should be defined as a functor class
-         * so that validation on the variable value can be done at parse
-         * time. This is a stop-gap.
-         */
-        variables.put(key, val);
-    }
-
-    /**
-     * Retrieves the value of a variable that was set in the .inputrc file
-     * during processing
-     * @param var The variable name
-     * @return The variable value.
-     */
-    public String getVariable(String var) {
-        return variables.get (var);
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4086 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-//import java.awt.*;
-//import java.awt.datatransfer.Clipboard;
-//import java.awt.datatransfer.DataFlavor;
-//import java.awt.datatransfer.Transferable;
-//import java.awt.datatransfer.UnsupportedFlavorException;
-//import java.awt.event.ActionListener;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.lang.System;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.ResourceBundle;
-import java.util.Stack;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import jdk.internal.jline.DefaultTerminal2;
-import jdk.internal.jline.Terminal;
-import jdk.internal.jline.Terminal2;
-import jdk.internal.jline.TerminalFactory;
-import jdk.internal.jline.UnixTerminal;
-import jdk.internal.jline.console.completer.CandidateListCompletionHandler;
-import jdk.internal.jline.console.completer.Completer;
-import jdk.internal.jline.console.completer.CompletionHandler;
-import jdk.internal.jline.console.history.History;
-import jdk.internal.jline.console.history.MemoryHistory;
-import jdk.internal.jline.internal.Ansi;
-import jdk.internal.jline.internal.Configuration;
-import jdk.internal.jline.internal.Curses;
-import jdk.internal.jline.internal.InputStreamReader;
-import jdk.internal.jline.internal.Log;
-import jdk.internal.jline.internal.NonBlockingInputStream;
-import jdk.internal.jline.internal.Nullable;
-import jdk.internal.jline.internal.TerminalLineSettings;
-import jdk.internal.jline.internal.Urls;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * A reader for console applications. It supports custom tab-completion,
- * saveable command history, and command line editing. On some platforms,
- * platform-specific commands will need to be issued before the reader will
- * function properly. See {@link jline.Terminal#init} for convenience
- * methods for issuing platform-specific setup commands.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- */
-public class ConsoleReader implements Closeable
-{
-    public static final String JLINE_NOBELL = "jline.nobell";
-
-    public static final String JLINE_ESC_TIMEOUT = "jline.esc.timeout";
-
-    public static final String JLINE_INPUTRC = "jline.inputrc";
-
-    public static final String INPUT_RC = ".inputrc";
-
-    public static final String DEFAULT_INPUT_RC = "/etc/inputrc";
-
-    public static final String JLINE_EXPAND_EVENTS = "jline.expandevents";
-
-    public static final char BACKSPACE = '\b';
-
-    public static final char RESET_LINE = '\r';
-
-    public static final char KEYBOARD_BELL = '\07';
-
-    public static final char NULL_MASK = 0;
-
-    public static final int TAB_WIDTH = 8;
-
-    private static final ResourceBundle
-        resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
-
-    private static final int ESCAPE = 27;
-    private static final int READ_EXPIRED = -2;
-
-    private final Terminal2 terminal;
-
-    private final Writer out;
-
-    private final CursorBuffer buf = new CursorBuffer();
-    private boolean cursorOk;
-
-    private String prompt;
-    private int    promptLen;
-
-    private boolean expandEvents = Configuration.getBoolean(JLINE_EXPAND_EVENTS, true);
-
-    private boolean bellEnabled = !Configuration.getBoolean(JLINE_NOBELL, true);
-
-    private boolean handleUserInterrupt = false;
-
-    private boolean handleLitteralNext = true;
-
-    private Character mask;
-
-    private Character echoCharacter;
-
-    private CursorBuffer originalBuffer = null;
-
-    private StringBuffer searchTerm = null;
-
-    private String previousSearchTerm = "";
-
-    private int searchIndex = -1;
-
-    private int parenBlinkTimeout = 500;
-
-    // Reading buffers
-    private final StringBuilder opBuffer = new StringBuilder();
-    private final Stack<Character> pushBackChar = new Stack<Character>();
-
-    /*
-     * The reader and the nonBlockingInput go hand-in-hand.  The reader wraps
-     * the nonBlockingInput, but we have to retain a handle to it so that
-     * we can shut down its blocking read thread when we go away.
-     */
-    private NonBlockingInputStream in;
-    private long                   escapeTimeout;
-    private Reader                 reader;
-
-    /**
-     * Last character searched for with a vi character search
-     */
-    private char  charSearchChar = 0;           // Character to search for
-    private char  charSearchLastInvokeChar = 0; // Most recent invocation key
-    private char  charSearchFirstInvokeChar = 0;// First character that invoked
-
-    /**
-     * The vi yank buffer
-     */
-    private String yankBuffer = "";
-
-    private KillRing killRing = new KillRing();
-
-    private String encoding;
-
-    private boolean quotedInsert;
-
-    private boolean recording;
-
-    private String macro = "";
-
-    private String appName;
-
-    private URL inputrcUrl;
-
-    private ConsoleKeys consoleKeys;
-
-    private String commentBegin = null;
-
-    private boolean skipLF = false;
-
-    /**
-     * Set to true if the reader should attempt to detect copy-n-paste. The
-     * effect of this that an attempt is made to detect if tab is quickly
-     * followed by another character, then it is assumed that the tab was
-     * a literal tab as part of a copy-and-paste operation and is inserted as
-     * such.
-     */
-    private boolean copyPasteDetection = false;
-
-    /*
-     * Current internal state of the line reader
-     */
-    private State   state = State.NORMAL;
-
-    /**
-     * Possible states in which the current readline operation may be in.
-     */
-    private static enum State {
-        /**
-         * The user is just typing away
-         */
-        NORMAL,
-        /**
-         * In the middle of a emacs seach
-         */
-        SEARCH,
-        FORWARD_SEARCH,
-        /**
-         * VI "yank-to" operation ("y" during move mode)
-         */
-        VI_YANK_TO,
-        /**
-         * VI "delete-to" operation ("d" during move mode)
-         */
-        VI_DELETE_TO,
-        /**
-         * VI "change-to" operation ("c" during move mode)
-         */
-        VI_CHANGE_TO
-    }
-
-    public ConsoleReader() throws IOException {
-        this(null, new FileInputStream(FileDescriptor.in), System.out, null);
-    }
-
-    public ConsoleReader(final InputStream in, final OutputStream out) throws IOException {
-        this(null, in, out, null);
-    }
-
-    public ConsoleReader(final InputStream in, final OutputStream out, final Terminal term) throws IOException {
-        this(null, in, out, term);
-    }
-
-    public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term) throws IOException {
-        this(appName, in, out, term, null);
-    }
-
-    public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term, final @Nullable String encoding)
-        throws IOException
-    {
-        this.appName = appName != null ? appName : "JLine";
-        this.encoding = encoding != null ? encoding : Configuration.getEncoding();
-        Terminal terminal = term != null ? term : TerminalFactory.get();
-        this.terminal = terminal instanceof Terminal2 ? (Terminal2) terminal : new DefaultTerminal2(terminal);
-        String outEncoding = terminal.getOutputEncoding() != null? terminal.getOutputEncoding() : this.encoding;
-        this.out = new OutputStreamWriter(terminal.wrapOutIfNeeded(out), outEncoding);
-        setInput( in );
-
-        this.inputrcUrl = getInputRc();
-
-        consoleKeys = new ConsoleKeys(this.appName, inputrcUrl);
-
-        if (terminal instanceof UnixTerminal
-                && TerminalLineSettings.DEFAULT_TTY.equals(((UnixTerminal) terminal).getSettings().getTtyDevice())
-                && Configuration.getBoolean("jline.sigcont", false)) {
-            setupSigCont();
-        }
-    }
-
-    private void setupSigCont() {
-        // Check that sun.misc.SignalHandler and sun.misc.Signal exists
-        try {
-            Class<?> signalClass = Class.forName("sun.misc.Signal");
-            Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
-            // Implement signal handler
-            Object signalHandler = Proxy.newProxyInstance(getClass().getClassLoader(),
-                    new Class<?>[]{signalHandlerClass}, new InvocationHandler() {
-                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                            // only method we are proxying is handle()
-                            terminal.init();
-                            try {
-                                drawLine();
-                                flush();
-                            } catch (IOException e) {
-                                e.printStackTrace();
-                            }
-                            return null;
-                        }
-                    });
-            // Register the signal handler, this code is equivalent to:
-            // Signal.handle(new Signal("CONT"), signalHandler);
-            signalClass.getMethod("handle", signalClass, signalHandlerClass).invoke(null, signalClass.getConstructor(String.class).newInstance("CONT"), signalHandler);
-        } catch (ClassNotFoundException cnfe) {
-            // sun.misc Signal handler classes don't exist
-        } catch (Exception e) {
-            // Ignore this one too, if the above failed, the signal API is incompatible with what we're expecting
-        }
-    }
-
-    /**
-     * Retrieve the URL for the inputrc configuration file in effect. Intended
-     * use is for instantiating ConsoleKeys, to read inputrc variables.
-     */
-    public static URL getInputRc() throws IOException {
-        String path = Configuration.getString(JLINE_INPUTRC);
-        if (path == null) {
-            File f = new File(Configuration.getUserHome(), INPUT_RC);
-            if (!f.exists()) {
-                f = new File(DEFAULT_INPUT_RC);
-            }
-            return f.toURI().toURL();
-        } else {
-            return Urls.create(path);
-        }
-    }
-
-    public KeyMap getKeys() {
-        return consoleKeys.getKeys();
-    }
-
-    void setInput(final InputStream in) throws IOException {
-        this.escapeTimeout = Configuration.getLong(JLINE_ESC_TIMEOUT, 100);
-        boolean nonBlockingEnabled =
-               escapeTimeout > 0L
-            && terminal.isSupported()
-            && in != null;
-
-        /*
-         * If we had a non-blocking thread already going, then shut it down
-         * and start a new one.
-         */
-        if (this.in != null) {
-            this.in.shutdown();
-        }
-
-        final InputStream wrapped = terminal.wrapInIfNeeded( in );
-
-        this.in = new NonBlockingInputStream(wrapped, nonBlockingEnabled);
-        this.reader = new InputStreamReader( this.in, encoding );
-    }
-
-    /**
-     * Shuts the console reader down.  This method should be called when you
-     * have completed using the reader as it shuts down and cleans up resources
-     * that would otherwise be "leaked".
-     */
-    @Override
-    public void close() {
-        if (in != null) {
-            in.shutdown();
-        }
-    }
-
-    /**
-     * Shuts the console reader down.  The same as {@link #close()}.
-     * @deprecated Use {@link #close()} instead.
-     */
-    @Deprecated
-    public void shutdown() {
-        this.close();
-    }
-
-    /**
-     * Shuts down the ConsoleReader if the JVM attempts to clean it up.
-     */
-    @Override
-    @SuppressWarnings("deprecation")
-    protected void finalize() throws Throwable {
-        try {
-            close();
-        }
-        finally {
-            super.finalize();
-        }
-    }
-
-    public InputStream getInput() {
-        return in;
-    }
-
-    public Writer getOutput() {
-        return out;
-    }
-
-    public Terminal getTerminal() {
-        return terminal;
-    }
-
-    public CursorBuffer getCursorBuffer() {
-        return buf;
-    }
-
-    public void setExpandEvents(final boolean expand) {
-        this.expandEvents = expand;
-    }
-
-    public boolean getExpandEvents() {
-        return expandEvents;
-    }
-
-    /**
-     * Enables or disables copy and paste detection. The effect of enabling this
-     * this setting is that when a tab is received immediately followed by another
-     * character, the tab will not be treated as a completion, but as a tab literal.
-     * @param onoff true if detection is enabled
-     */
-    public void setCopyPasteDetection(final boolean onoff) {
-        copyPasteDetection = onoff;
-    }
-
-    /**
-     * @return true if copy and paste detection is enabled.
-     */
-    public boolean isCopyPasteDetectionEnabled() {
-        return copyPasteDetection;
-    }
-
-    /**
-     * Set whether the console bell is enabled.
-     *
-     * @param enabled true if enabled; false otherwise
-     * @since 2.7
-     */
-    public void setBellEnabled(boolean enabled) {
-        this.bellEnabled = enabled;
-    }
-
-    /**
-     * Get whether the console bell is enabled
-     *
-     * @return true if enabled; false otherwise
-     * @since 2.7
-     */
-    public boolean getBellEnabled() {
-        return bellEnabled;
-    }
-
-    /**
-     * Set whether user interrupts (ctrl-C) are handled by having JLine
-     * throw {@link UserInterruptException} from {@link #readLine}.
-     * Otherwise, the JVM will handle {@code SIGINT} as normal, which
-     * usually causes it to exit. The default is {@code false}.
-     *
-     * @since 2.10
-     */
-    public void setHandleUserInterrupt(boolean enabled)
-    {
-        this.handleUserInterrupt = enabled;
-    }
-
-    /**
-     * Get whether user interrupt handling is enabled
-     *
-     * @return true if enabled; false otherwise
-     * @since 2.10
-     */
-    public boolean getHandleUserInterrupt()
-    {
-        return handleUserInterrupt;
-    }
-
-    /**
-     * Set wether literal next are handled by JLine.
-     *
-     * @since 2.13
-     */
-    public void setHandleLitteralNext(boolean handleLitteralNext) {
-        this.handleLitteralNext = handleLitteralNext;
-    }
-
-    /**
-     * Get wether literal next are handled by JLine.
-     *
-     * @since 2.13
-     */
-    public boolean getHandleLitteralNext() {
-        return handleLitteralNext;
-    }
-
-    /**
-     * Sets the string that will be used to start a comment when the
-     * insert-comment key is struck.
-     * @param commentBegin The begin comment string.
-     * @since 2.7
-     */
-    public void setCommentBegin(String commentBegin) {
-        this.commentBegin = commentBegin;
-    }
-
-    /**
-     * @return the string that will be used to start a comment when the
-     * insert-comment key is struck.
-     * @since 2.7
-     */
-    public String getCommentBegin() {
-        String str = commentBegin;
-
-        if (str == null) {
-            str = consoleKeys.getVariable("comment-begin");
-            if (str == null) {
-                str = "#";
-            }
-        }
-        return str;
-    }
-
-    public void setPrompt(final String prompt) {
-        this.prompt = prompt;
-        this.promptLen = (prompt == null) ? 0 : wcwidth(Ansi.stripAnsi(lastLine(prompt)), 0);
-    }
-
-    public String getPrompt() {
-        return prompt;
-    }
-
-    /**
-     * Set the echo character. For example, to have "*" entered when a password is typed:
-     * <pre>
-     * myConsoleReader.setEchoCharacter(new Character('*'));
-     * </pre>
-     * Setting the character to <code>null</code> will restore normal character echoing.<p/>
-     * Setting the character to <code>Character.valueOf(0)</code> will cause nothing to be echoed.
-     *
-     * @param c the character to echo to the console in place of the typed character.
-     */
-    public void setEchoCharacter(final Character c) {
-        this.echoCharacter = c;
-    }
-
-    /**
-     * Returns the echo character.
-     */
-    public Character getEchoCharacter() {
-        return echoCharacter;
-    }
-
-    /**
-     * Erase the current line.
-     *
-     * @return false if we failed (e.g., the buffer was empty)
-     */
-    protected final boolean resetLine() throws IOException {
-        if (buf.cursor == 0) {
-            return false;
-        }
-
-        StringBuilder killed = new StringBuilder();
-
-        while (buf.cursor > 0) {
-            char c = buf.current();
-            if (c == 0) {
-                break;
-            }
-
-            killed.append(c);
-            backspace();
-        }
-
-        String copy = killed.reverse().toString();
-        killRing.addBackwards(copy);
-
-        return true;
-    }
-
-    int wcwidth(CharSequence str, int pos) {
-        return wcwidth(str, 0, str.length(), pos);
-    }
-
-    int wcwidth(CharSequence str, int start, int end, int pos) {
-        int cur = pos;
-        for (int i = start; i < end;) {
-            int ucs;
-            char c1 = str.charAt(i++);
-            if (!Character.isHighSurrogate(c1) || i >= end) {
-                ucs = c1;
-            } else {
-                char c2 = str.charAt(i);
-                if (Character.isLowSurrogate(c2)) {
-                    i++;
-                    ucs = Character.toCodePoint(c1, c2);
-                } else {
-                    ucs = c1;
-                }
-            }
-            cur += wcwidth(ucs, cur);
-        }
-        return cur - pos;
-    }
-
-    int wcwidth(int ucs, int pos) {
-        if (ucs == '\t') {
-            return nextTabStop(pos);
-        } else if (ucs < 32) {
-            return 2;
-        } else  {
-            int w = WCWidth.wcwidth(ucs);
-            return w > 0 ? w : 0;
-        }
-    }
-
-    int nextTabStop(int pos) {
-        int tabWidth = TAB_WIDTH;
-        int width = getTerminal().getWidth();
-        int mod = (pos + tabWidth - 1) % tabWidth;
-        int npos = pos + tabWidth - mod;
-        return npos < width ? npos - pos : width - pos;
-    }
-
-    int getCursorPosition() {
-        return promptLen + wcwidth(buf.buffer, 0, buf.cursor, promptLen);
-    }
-
-    /**
-     * Returns the text after the last '\n'.
-     * prompt is returned if no '\n' characters are present.
-     * null is returned if prompt is null.
-     */
-    private static String lastLine(String str) {
-        if (str == null) return "";
-        int last = str.lastIndexOf("\n");
-
-        if (last >= 0) {
-            return str.substring(last + 1, str.length());
-        }
-
-        return str;
-    }
-
-    /**
-     * Move the cursor position to the specified absolute index.
-     */
-    public boolean setCursorPosition(final int position) throws IOException {
-        if (position == buf.cursor) {
-            return true;
-        }
-
-        return moveCursor(position - buf.cursor) != 0;
-    }
-
-    /**
-     * Set the current buffer's content to the specified {@link String}. The
-     * visual console will be modified to show the current buffer.
-     *
-     * @param buffer the new contents of the buffer.
-     */
-    private void setBuffer(final String buffer) throws IOException {
-        // don't bother modifying it if it is unchanged
-        if (buffer.equals(buf.buffer.toString())) {
-            return;
-        }
-
-        // obtain the difference between the current buffer and the new one
-        int sameIndex = 0;
-
-        for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
-            && (i < l2); i++) {
-            if (buffer.charAt(i) == buf.buffer.charAt(i)) {
-                sameIndex++;
-            }
-            else {
-                break;
-            }
-        }
-
-        int diff = buf.cursor - sameIndex;
-        if (diff < 0) { // we can't backspace here so try from the end of the buffer
-            moveToEnd();
-            diff = buf.buffer.length() - sameIndex;
-        }
-
-        backspace(diff); // go back for the differences
-        killLine(); // clear to the end of the line
-        buf.buffer.setLength(sameIndex); // the new length
-        putString(buffer.substring(sameIndex)); // append the differences
-    }
-
-    private void setBuffer(final CharSequence buffer) throws IOException {
-        setBuffer(String.valueOf(buffer));
-    }
-
-    private void setBufferKeepPos(final String buffer) throws IOException {
-        int pos = buf.cursor;
-        setBuffer(buffer);
-        setCursorPosition(pos);
-    }
-
-    private void setBufferKeepPos(final CharSequence buffer) throws IOException {
-        setBufferKeepPos(String.valueOf(buffer));
-    }
-
-    /**
-     * Output put the prompt + the current buffer
-     */
-    public void drawLine() throws IOException {
-        String prompt = getPrompt();
-        if (prompt != null) {
-            rawPrint(prompt);
-        }
-
-        fmtPrint(buf.buffer, 0, buf.cursor, promptLen);
-
-        // force drawBuffer to check for weird wrap (after clear screen)
-        drawBuffer();
-    }
-
-    /**
-     * Clear the line and redraw it.
-     */
-    public void redrawLine() throws IOException {
-        tputs("carriage_return");
-        drawLine();
-    }
-
-    /**
-     * Clear the buffer and add its contents to the history.
-     *
-     * @return the former contents of the buffer.
-     */
-    final String finishBuffer() throws IOException { // FIXME: Package protected because used by tests
-        String str = buf.buffer.toString();
-        String historyLine = str;
-
-        if (expandEvents) {
-            try {
-                str = expandEvents(str);
-                // all post-expansion occurrences of '!' must have been escaped, so re-add escape to each
-                historyLine = str.replace("!", "\\!");
-                // only leading '^' results in expansion, so only re-add escape for that case
-                historyLine = historyLine.replaceAll("^\\^", "\\\\^");
-            } catch(IllegalArgumentException e) {
-                Log.error("Could not expand event", e);
-                beep();
-                buf.clear();
-                str = "";
-            }
-        }
-
-        // we only add it to the history if the buffer is not empty
-        // and if mask is null, since having a mask typically means
-        // the string was a password. We clear the mask after this call
-        if (str.length() > 0) {
-            if (mask == null && isHistoryEnabled()) {
-                history.add(historyLine);
-            }
-            else {
-                mask = null;
-            }
-        }
-
-        history.moveToEnd();
-
-        buf.buffer.setLength(0);
-        buf.cursor = 0;
-
-        return str;
-    }
-
-    /**
-     * Expand event designator such as !!, !#, !3, etc...
-     * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
-     */
-    @SuppressWarnings("fallthrough")
-    protected String expandEvents(String str) throws IOException {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < str.length(); i++) {
-            char c = str.charAt(i);
-            switch (c) {
-                case '\\':
-                    // any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
-                    // a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
-                    // otherwise, add the escape
-                    if (i + 1 < str.length()) {
-                        char nextChar = str.charAt(i+1);
-                        if (nextChar == '!' || (nextChar == '^' && i == 0)) {
-                            c = nextChar;
-                            i++;
-                        }
-                    }
-                    sb.append(c);
-                    break;
-                case '!':
-                    if (i + 1 < str.length()) {
-                        c = str.charAt(++i);
-                        boolean neg = false;
-                        String rep = null;
-                        int i1, idx;
-                        switch (c) {
-                            case '!':
-                                if (history.size() == 0) {
-                                    throw new IllegalArgumentException("!!: event not found");
-                                }
-                                rep = history.get(history.index() - 1).toString();
-                                break;
-                            case '#':
-                                sb.append(sb.toString());
-                                break;
-                            case '?':
-                                i1 = str.indexOf('?', i + 1);
-                                if (i1 < 0) {
-                                    i1 = str.length();
-                                }
-                                String sc = str.substring(i + 1, i1);
-                                i = i1;
-                                idx = searchBackwards(sc);
-                                if (idx < 0) {
-                                    throw new IllegalArgumentException("!?" + sc + ": event not found");
-                                } else {
-                                    rep = history.get(idx).toString();
-                                }
-                                break;
-                            case '$':
-                                if (history.size() == 0) {
-                                    throw new IllegalArgumentException("!$: event not found");
-                                }
-                                String previous = history.get(history.index() - 1).toString().trim();
-                                int lastSpace = previous.lastIndexOf(' ');
-                                if(lastSpace != -1) {
-                                    rep = previous.substring(lastSpace+1);
-                                } else {
-                                    rep = previous;
-                                }
-                                break;
-                            case ' ':
-                            case '\t':
-                                sb.append('!');
-                                sb.append(c);
-                                break;
-                            case '-':
-                                neg = true;
-                                i++;
-                                // fall through
-                            case '0':
-                            case '1':
-                            case '2':
-                            case '3':
-                            case '4':
-                            case '5':
-                            case '6':
-                            case '7':
-                            case '8':
-                            case '9':
-                                i1 = i;
-                                for (; i < str.length(); i++) {
-                                    c = str.charAt(i);
-                                    if (c < '0' || c > '9') {
-                                        break;
-                                    }
-                                }
-                                idx = 0;
-                                try {
-                                    idx = Integer.parseInt(str.substring(i1, i));
-                                } catch (NumberFormatException e) {
-                                    throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
-                                }
-                                if (neg) {
-                                    if (idx > 0 && idx <= history.size()) {
-                                        rep = (history.get(history.index() - idx)).toString();
-                                    } else {
-                                        throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
-                                    }
-                                } else {
-                                    if (idx > history.index() - history.size() && idx <= history.index()) {
-                                        rep = (history.get(idx - 1)).toString();
-                                    } else {
-                                        throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
-                                    }
-                                }
-                                break;
-                            default:
-                                String ss = str.substring(i);
-                                i = str.length();
-                                idx = searchBackwards(ss, history.index(), true);
-                                if (idx < 0) {
-                                    throw new IllegalArgumentException("!" + ss + ": event not found");
-                                } else {
-                                    rep = history.get(idx).toString();
-                                }
-                                break;
-                        }
-                        if (rep != null) {
-                            sb.append(rep);
-                        }
-                    } else {
-                        sb.append(c);
-                    }
-                    break;
-                case '^':
-                    if (i == 0) {
-                        int i1 = str.indexOf('^', i + 1);
-                        int i2 = str.indexOf('^', i1 + 1);
-                        if (i2 < 0) {
-                            i2 = str.length();
-                        }
-                        if (i1 > 0 && i2 > 0) {
-                            String s1 = str.substring(i + 1, i1);
-                            String s2 = str.substring(i1 + 1, i2);
-                            String s = history.get(history.index() - 1).toString().replace(s1, s2);
-                            sb.append(s);
-                            i = i2 + 1;
-                            break;
-                        }
-                    }
-                    sb.append(c);
-                    break;
-                default:
-                    sb.append(c);
-                    break;
-            }
-        }
-        String result = sb.toString();
-        if (!str.equals(result)) {
-            fmtPrint(result, getCursorPosition());
-            println();
-            flush();
-        }
-        return result;
-
-    }
-
-    /**
-     * Write out the specified string to the buffer and the output stream.
-     */
-    public void putString(final CharSequence str) throws IOException {
-        int pos = getCursorPosition();
-        buf.write(str);
-        if (mask == null) {
-            // no masking
-            fmtPrint(str, pos);
-        } else if (mask == NULL_MASK) {
-            // don't print anything
-        } else {
-            rawPrint(mask, str.length());
-        }
-        drawBuffer();
-    }
-
-    /**
-     * Redraw the rest of the buffer from the cursor onwards. This is necessary
-     * for inserting text into the buffer.
-     *
-     * @param clear the number of characters to clear after the end of the buffer
-     */
-    private void drawBuffer(final int clear) throws IOException {
-        // debug ("drawBuffer: " + clear);
-        int nbChars = buf.length() - buf.cursor;
-        if (buf.cursor != buf.length() || clear != 0) {
-            if (mask != null) {
-                if (mask != NULL_MASK) {
-                    rawPrint(mask, nbChars);
-                } else {
-                    nbChars = 0;
-                }
-            } else {
-                fmtPrint(buf.buffer, buf.cursor, buf.length());
-            }
-        }
-        int cursorPos = promptLen + wcwidth(buf.buffer, 0, buf.length(), promptLen);
-        if (terminal.hasWeirdWrap() && !cursorOk) {
-            int width = terminal.getWidth();
-            // best guess on whether the cursor is in that weird location...
-            // Need to do this without calling ansi cursor location methods
-            // otherwise it breaks paste of wrapped lines in xterm.
-            if (cursorPos > 0 && (cursorPos % width == 0)) {
-                // the following workaround is reverse-engineered from looking
-                // at what bash sent to the terminal in the same situation
-                rawPrint(' '); // move cursor to next line by printing dummy space
-                tputs("carriage_return"); // CR / not newline.
-            }
-            cursorOk = true;
-        }
-        clearAhead(clear, cursorPos);
-        back(nbChars);
-    }
-
-    /**
-     * Redraw the rest of the buffer from the cursor onwards. This is necessary
-     * for inserting text into the buffer.
-     */
-    private void drawBuffer() throws IOException {
-        drawBuffer(0);
-    }
-
-    /**
-     * Clear ahead the specified number of characters without moving the cursor.
-     *
-     * @param num the number of characters to clear
-     * @param pos the current screen cursor position
-     */
-    private void clearAhead(int num, final int pos) throws IOException {
-        if (num == 0) return;
-
-        int width = terminal.getWidth();
-        // Use kill line
-        if (terminal.getStringCapability("clr_eol") != null) {
-            int cur = pos;
-            int c0 = cur % width;
-            // Erase end of current line
-            int nb = Math.min(num, width - c0);
-            tputs("clr_eol");
-            num -= nb;
-            // Loop
-            while (num > 0) {
-                // Move to beginning of next line
-                int prev = cur;
-                cur = cur - cur % width + width;
-                moveCursorFromTo(prev, cur);
-                // Erase
-                nb = Math.min(num, width);
-                tputs("clr_eol");
-                num -= nb;
-            }
-            moveCursorFromTo(cur, pos);
-        }
-        // Terminal does not wrap on the right margin
-        else if (!terminal.getBooleanCapability("auto_right_margin")) {
-            int cur = pos;
-            int c0 = cur % width;
-            // Erase end of current line
-            int nb = Math.min(num, width - c0);
-            rawPrint(' ', nb);
-            num -= nb;
-            cur += nb;
-            // Loop
-            while (num > 0) {
-                // Move to beginning of next line
-                moveCursorFromTo(cur, ++cur);
-                // Erase
-                nb = Math.min(num, width);
-                rawPrint(' ', nb);
-                num -= nb;
-                cur += nb;
-            }
-            moveCursorFromTo(cur, pos);
-        }
-        // Simple erasure
-        else {
-            rawPrint(' ', num);
-            moveCursorFromTo(pos + num, pos);
-        }
-    }
-
-    /**
-     * Move the visual cursor backward without modifying the buffer cursor.
-     */
-    protected void back(final int num) throws IOException {
-        if (num == 0) return;
-        int i0 = promptLen + wcwidth(buf.buffer, 0, buf.cursor, promptLen);
-        int i1 = i0 + ((mask != null) ? num : wcwidth(buf.buffer, buf.cursor, buf.cursor + num, i0));
-        moveCursorFromTo(i1, i0);
-    }
-
-    /**
-     * Flush the console output stream. This is important for printout out single characters (like a backspace or
-     * keyboard) that we want the console to handle immediately.
-     */
-    public void flush() throws IOException {
-        out.flush();
-    }
-
-    private int backspaceAll() throws IOException {
-        return backspace(Integer.MAX_VALUE);
-    }
-
-    /**
-     * Issue <em>num</em> backspaces.
-     *
-     * @return the number of characters backed up
-     */
-    private int backspace(final int num) throws IOException {
-        if (buf.cursor == 0) {
-            return 0;
-        }
-
-        int count = - moveCursor(-num);
-        int clear = wcwidth(buf.buffer, buf.cursor, buf.cursor + count, getCursorPosition());
-        buf.buffer.delete(buf.cursor, buf.cursor + count);
-
-        drawBuffer(clear);
-        return count;
-    }
-
-    /**
-     * Issue a backspace.
-     *
-     * @return true if successful
-     */
-    public boolean backspace() throws IOException {
-        return backspace(1) == 1;
-    }
-
-    protected boolean moveToEnd() throws IOException {
-        if (buf.cursor == buf.length()) {
-            return true;
-        }
-        return moveCursor(buf.length() - buf.cursor) > 0;
-    }
-
-    /**
-     * Delete the character at the current position and redraw the remainder of the buffer.
-     */
-    private boolean deleteCurrentCharacter() throws IOException {
-        if (buf.length() == 0 || buf.cursor == buf.length()) {
-            return false;
-        }
-
-        buf.buffer.deleteCharAt(buf.cursor);
-        drawBuffer(1);
-        return true;
-    }
-
-    /**
-     * This method is calling while doing a delete-to ("d"), change-to ("c"),
-     * or yank-to ("y") and it filters out only those movement operations
-     * that are allowable during those operations. Any operation that isn't
-     * allow drops you back into movement mode.
-     *
-     * @param op The incoming operation to remap
-     * @return The remaped operation
-     */
-    private Operation viDeleteChangeYankToRemap (Operation op) {
-        switch (op) {
-            case VI_EOF_MAYBE:
-            case ABORT:
-            case BACKWARD_CHAR:
-            case FORWARD_CHAR:
-            case END_OF_LINE:
-            case VI_MATCH:
-            case VI_BEGINNING_OF_LINE_OR_ARG_DIGIT:
-            case VI_ARG_DIGIT:
-            case VI_PREV_WORD:
-            case VI_END_WORD:
-            case VI_CHAR_SEARCH:
-            case VI_NEXT_WORD:
-            case VI_FIRST_PRINT:
-            case VI_GOTO_MARK:
-            case VI_COLUMN:
-            case VI_DELETE_TO:
-            case VI_YANK_TO:
-            case VI_CHANGE_TO:
-                return op;
-
-            default:
-                return Operation.VI_MOVEMENT_MODE;
-        }
-    }
-
-    /**
-     * Deletes the previous character from the cursor position
-     * @param count number of times to do it.
-     * @return true if it was done.
-     */
-    private boolean viRubout(int count) throws IOException {
-        boolean ok = true;
-        for (int i = 0; ok && i < count; i++) {
-            ok = backspace();
-        }
-        return ok;
-    }
-
-    /**
-     * Deletes the character you are sitting on and sucks the rest of
-     * the line in from the right.
-     * @param count Number of times to perform the operation.
-     * @return true if its works, false if it didn't
-     */
-    private boolean viDelete(int count) throws IOException {
-        boolean ok = true;
-        for (int i = 0; ok && i < count; i++) {
-            ok = deleteCurrentCharacter();
-        }
-        return ok;
-    }
-
-    /**
-     * Switches the case of the current character from upper to lower
-     * or lower to upper as necessary and advances the cursor one
-     * position to the right.
-     * @param count The number of times to repeat
-     * @return true if it completed successfully, false if not all
-     *   case changes could be completed.
-     */
-    private boolean viChangeCase(int count) throws IOException {
-        boolean ok = true;
-        for (int i = 0; ok && i < count; i++) {
-
-            ok = buf.cursor < buf.buffer.length ();
-            if (ok) {
-                char ch = buf.buffer.charAt(buf.cursor);
-                if (Character.isUpperCase(ch)) {
-                    ch = Character.toLowerCase(ch);
-                }
-                else if (Character.isLowerCase(ch)) {
-                    ch = Character.toUpperCase(ch);
-                }
-                buf.buffer.setCharAt(buf.cursor, ch);
-                drawBuffer(1);
-                moveCursor(1);
-            }
-        }
-        return ok;
-    }
-
-    /**
-     * Implements the vi change character command (in move-mode "r"
-     * followed by the character to change to).
-     * @param count Number of times to perform the action
-     * @param c The character to change to
-     * @return Whether or not there were problems encountered
-     */
-    private boolean viChangeChar(int count, int c) throws IOException {
-        // EOF, ESC, or CTRL-C aborts.
-        if (c < 0 || c == '\033' || c == '\003') {
-            return true;
-        }
-
-        boolean ok = true;
-        for (int i = 0; ok && i < count; i++) {
-            ok = buf.cursor < buf.buffer.length ();
-            if (ok) {
-                buf.buffer.setCharAt(buf.cursor, (char) c);
-                drawBuffer(1);
-                if (i < (count-1)) {
-                    moveCursor(1);
-                }
-            }
-        }
-        return ok;
-    }
-
-    /**
-     * This is a close facsimile of the actual vi previous word logic. In
-     * actual vi words are determined by boundaries of identity characterse.
-     * This logic is a bit more simple and simply looks at white space or
-     * digits or characters.  It should be revised at some point.
-     *
-     * @param count number of iterations
-     * @return true if the move was successful, false otherwise
-     */
-    private boolean viPreviousWord(int count) throws IOException {
-        boolean ok = true;
-        if (buf.cursor == 0) {
-            return false;
-        }
-
-        int pos = buf.cursor - 1;
-        for (int i = 0; pos > 0 && i < count; i++) {
-            // If we are on white space, then move back.
-            while (pos > 0 && isWhitespace(buf.buffer.charAt(pos))) {
-                --pos;
-            }
-
-            while (pos > 0 && !isDelimiter(buf.buffer.charAt(pos-1))) {
-                --pos;
-            }
-
-            if (pos > 0 && i < (count-1)) {
-                --pos;
-            }
-        }
-        setCursorPosition(pos);
-        return ok;
-    }
-
-    /**
-     * Performs the vi "delete-to" action, deleting characters between a given
-     * span of the input line.
-     * @param startPos The start position
-     * @param endPos The end position.
-     * @param isChange If true, then the delete is part of a change operationg
-     *    (e.g. "c$" is change-to-end-of line, so we first must delete to end
-     *    of line to start the change
-     * @return true if it succeeded, false otherwise
-     */
-    private boolean viDeleteTo(int startPos, int endPos, boolean isChange) throws IOException {
-        if (startPos == endPos) {
-            return true;
-        }
-
-        if (endPos < startPos) {
-            int tmp = endPos;
-            endPos = startPos;
-            startPos = tmp;
-        }
-
-        setCursorPosition(startPos);
-        buf.cursor = startPos;
-        buf.buffer.delete(startPos, endPos);
-        drawBuffer(endPos - startPos);
-
-        // If we are doing a delete operation (e.g. "d$") then don't leave the
-        // cursor dangling off the end. In reality the "isChange" flag is silly
-        // what is really happening is that if we are in "move-mode" then the
-        // cursor can't be moved off the end of the line, but in "edit-mode" it
-        // is ok, but I have no easy way of knowing which mode we are in.
-        if (! isChange && startPos > 0 && startPos == buf.length()) {
-            moveCursor(-1);
-        }
-        return true;
-    }
-
-    /**
-     * Implement the "vi" yank-to operation.  This operation allows you
-     * to yank the contents of the current line based upon a move operation,
-     * for exaple "yw" yanks the current word, "3yw" yanks 3 words, etc.
-     *
-     * @param startPos The starting position from which to yank
-     * @param endPos The ending position to which to yank
-     * @return true if the yank succeeded
-     */
-    private boolean viYankTo(int startPos, int endPos) throws IOException {
-        int cursorPos = startPos;
-
-        if (endPos < startPos) {
-            int tmp = endPos;
-            endPos = startPos;
-            startPos = tmp;
-        }
-
-        if (startPos == endPos) {
-            yankBuffer = "";
-            return true;
-        }
-
-        yankBuffer = buf.buffer.substring(startPos, endPos);
-
-        /*
-         * It was a movement command that moved the cursor to find the
-         * end position, so put the cursor back where it started.
-         */
-        setCursorPosition(cursorPos);
-        return true;
-    }
-
-    /**
-     * Pasts the yank buffer to the right of the current cursor position
-     * and moves the cursor to the end of the pasted region.
-     *
-     * @param count Number of times to perform the operation.
-     * @return true if it worked, false otherwise
-     */
-    private boolean viPut(int count) throws IOException {
-        if (yankBuffer.length () == 0) {
-            return true;
-        }
-        if (buf.cursor < buf.buffer.length ()) {
-            moveCursor(1);
-        }
-        for (int i = 0; i < count; i++) {
-            putString(yankBuffer);
-        }
-        moveCursor(-1);
-        return true;
-    }
-
-    /**
-     * Searches forward of the current position for a character and moves
-     * the cursor onto it.
-     * @param count Number of times to repeat the process.
-     * @param ch The character to search for
-     * @return true if the char was found, false otherwise
-     */
-    private boolean viCharSearch(int count, int invokeChar, int ch) throws IOException {
-        if (ch < 0 || invokeChar < 0) {
-            return false;
-        }
-
-        char    searchChar = (char)ch;
-        boolean isForward;
-        boolean stopBefore;
-
-        /*
-         * The character stuff turns out to be hairy. Here is how it works:
-         *   f - search forward for ch
-         *   F - search backward for ch
-         *   t - search forward for ch, but stop just before the match
-         *   T - search backward for ch, but stop just after the match
-         *   ; - After [fFtT;], repeat the last search, after ',' reverse it
-         *   , - After [fFtT;], reverse the last search, after ',' repeat it
-         */
-        if (invokeChar == ';' || invokeChar == ',') {
-            // No recent search done? Then bail
-            if (charSearchChar == 0) {
-                return false;
-            }
-
-            // Reverse direction if switching between ',' and ';'
-            if (charSearchLastInvokeChar == ';' || charSearchLastInvokeChar == ',') {
-                if (charSearchLastInvokeChar != invokeChar) {
-                    charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
-                }
-            }
-            else {
-                if (invokeChar == ',') {
-                    charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
-                }
-            }
-
-            searchChar = charSearchChar;
-        }
-        else {
-            charSearchChar            = searchChar;
-            charSearchFirstInvokeChar = (char) invokeChar;
-        }
-
-        charSearchLastInvokeChar = (char)invokeChar;
-
-        isForward = Character.isLowerCase(charSearchFirstInvokeChar);
-        stopBefore = (Character.toLowerCase(charSearchFirstInvokeChar) == 't');
-
-        boolean ok = false;
-
-        if (isForward) {
-            while (count-- > 0) {
-                int pos = buf.cursor + 1;
-                while (pos < buf.buffer.length()) {
-                    if (buf.buffer.charAt(pos) == searchChar) {
-                        setCursorPosition(pos);
-                        ok = true;
-                        break;
-                    }
-                    ++pos;
-                }
-            }
-
-            if (ok) {
-                if (stopBefore)
-                    moveCursor(-1);
-
-                /*
-                 * When in yank-to, move-to, del-to state we actually want to
-                 * go to the character after the one we landed on to make sure
-                 * that the character we ended up on is included in the
-                 * operation
-                 */
-                if (isInViMoveOperationState()) {
-                    moveCursor(1);
-                }
-            }
-        }
-        else {
-            while (count-- > 0) {
-                int pos = buf.cursor - 1;
-                while (pos >= 0) {
-                    if (buf.buffer.charAt(pos) == searchChar) {
-                        setCursorPosition(pos);
-                        ok = true;
-                        break;
-                    }
-                    --pos;
-                }
-            }
-
-            if (ok && stopBefore)
-                moveCursor(1);
-        }
-
-        return ok;
-    }
-
-    private static char switchCase(char ch) {
-        if (Character.isUpperCase(ch)) {
-            return Character.toLowerCase(ch);
-        }
-        return Character.toUpperCase(ch);
-    }
-
-    /**
-     * @return true if line reader is in the middle of doing a change-to
-     *   delete-to or yank-to.
-     */
-    private final boolean isInViMoveOperationState() {
-        return state == State.VI_CHANGE_TO
-            || state == State.VI_DELETE_TO
-            || state == State.VI_YANK_TO;
-    }
-
-    /**
-     * This is a close facsimile of the actual vi next word logic.
-     * As with viPreviousWord() this probably needs to be improved
-     * at some point.
-     *
-     * @param count number of iterations
-     * @return true if the move was successful, false otherwise
-     */
-    private boolean viNextWord(int count) throws IOException {
-        int pos = buf.cursor;
-        int end = buf.buffer.length();
-
-        for (int i = 0; pos < end && i < count; i++) {
-            // Skip over letter/digits
-            while (pos < end && !isDelimiter(buf.buffer.charAt(pos))) {
-                ++pos;
-            }
-
-            /*
-             * Don't you love special cases? During delete-to and yank-to
-             * operations the word movement is normal. However, during a
-             * change-to, the trailing spaces behind the last word are
-             * left in tact.
-             */
-            if (i < (count-1) || !(state == State.VI_CHANGE_TO)) {
-                while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
-                    ++pos;
-                }
-            }
-        }
-
-        setCursorPosition(pos);
-        return true;
-    }
-
-    /**
-     * Implements a close facsimile of the vi end-of-word movement.
-     * If the character is on white space, it takes you to the end
-     * of the next word.  If it is on the last character of a word
-     * it takes you to the next of the next word.  Any other character
-     * of a word, takes you to the end of the current word.
-     *
-     * @param count Number of times to repeat the action
-     * @return true if it worked.
-     */
-    private boolean viEndWord(int count) throws IOException {
-        int pos = buf.cursor;
-        int end = buf.buffer.length();
-
-        for (int i = 0; pos < end && i < count; i++) {
-            if (pos < (end-1)
-                    && !isDelimiter(buf.buffer.charAt(pos))
-                    && isDelimiter(buf.buffer.charAt (pos+1))) {
-                ++pos;
-            }
-
-            // If we are on white space, then move back.
-            while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
-                ++pos;
-            }
-
-            while (pos < (end-1) && !isDelimiter(buf.buffer.charAt(pos+1))) {
-                ++pos;
-            }
-        }
-        setCursorPosition(pos);
-        return true;
-    }
-
-    private boolean previousWord() throws IOException {
-        while (isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
-            // nothing
-        }
-
-        while (!isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
-            // nothing
-        }
-
-        return true;
-    }
-
-    private boolean nextWord() throws IOException {
-        while (isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
-            // nothing
-        }
-
-        while (!isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
-            // nothing
-        }
-
-        return true;
-    }
-
-    /**
-     * Deletes to the beginning of the word that the cursor is sitting on.
-     * If the cursor is on white-space, it deletes that and to the beginning
-     * of the word before it.  If the user is not on a word or whitespace
-     * it deletes up to the end of the previous word.
-     *
-     * @param count Number of times to perform the operation
-     * @return true if it worked, false if you tried to delete too many words
-     */
-    private boolean unixWordRubout(int count) throws IOException {
-        boolean success = true;
-        StringBuilder killed = new StringBuilder();
-
-        for (; count > 0; --count) {
-            if (buf.cursor == 0) {
-                success = false;
-                break;
-            }
-
-            while (isWhitespace(buf.current())) {
-                char c = buf.current();
-                if (c == 0) {
-                    break;
-                }
-
-                killed.append(c);
-                backspace();
-            }
-
-            while (!isWhitespace(buf.current())) {
-                char c = buf.current();
-                if (c == 0) {
-                    break;
-                }
-
-                killed.append(c);
-                backspace();
-            }
-        }
-
-        String copy = killed.reverse().toString();
-        killRing.addBackwards(copy);
-
-        return success;
-    }
-
-    private String insertComment(boolean isViMode) throws IOException {
-        String comment = this.getCommentBegin();
-        setCursorPosition(0);
-        putString(comment);
-        if (isViMode) {
-            consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-        }
-        return accept();
-    }
-
-    /**
-     * Implements vi search ("/" or "?").
-     */
-    @SuppressWarnings("fallthrough")
-    private int viSearch(char searchChar) throws IOException {
-        boolean isForward = (searchChar == '/');
-
-        /*
-         * This is a little gross, I'm sure there is a more appropriate way
-         * of saving and restoring state.
-         */
-        CursorBuffer origBuffer = buf.copy();
-
-        // Clear the contents of the current line and
-        setCursorPosition (0);
-        killLine();
-
-        // Our new "prompt" is the character that got us into search mode.
-        putString(Character.toString(searchChar));
-        flush();
-
-        boolean isAborted = false;
-        boolean isComplete = false;
-
-        /*
-         * Readline doesn't seem to do any special character map handling
-         * here, so I think we are safe.
-         */
-        int ch = -1;
-        while (!isAborted && !isComplete && (ch = readCharacter()) != -1) {
-            switch (ch) {
-                case '\033':  // ESC
-                    /*
-                     * The ESC behavior doesn't appear to be readline behavior,
-                     * but it is a little tweak of my own. I like it.
-                     */
-                    isAborted = true;
-                    break;
-                case '\010':  // Backspace
-                case '\177':  // Delete
-                    backspace();
-                    /*
-                     * Backspacing through the "prompt" aborts the search.
-                     */
-                    if (buf.cursor == 0) {
-                        isAborted = true;
-                    }
-                    break;
-                case '\012': // NL
-                case '\015': // CR
-                    isComplete = true;
-                    break;
-                default:
-                    putString(Character.toString((char) ch));
-            }
-
-            flush();
-        }
-
-        // If we aborted, then put ourself at the end of the original buffer.
-        if (ch == -1 || isAborted) {
-            setCursorPosition(0);
-            killLine();
-            putString(origBuffer.buffer);
-            setCursorPosition(origBuffer.cursor);
-            return -1;
-        }
-
-        /*
-         * The first character of the buffer was the search character itself
-         * so we discard it.
-         */
-        String searchTerm = buf.buffer.substring(1);
-        int idx = -1;
-
-        /*
-         * The semantics of the history thing is gross when you want to
-         * explicitly iterate over entries (without an iterator) as size()
-         * returns the actual number of entries in the list but get()
-         * doesn't work the way you think.
-         */
-        int end   = history.index();
-        int start = (end <= history.size()) ? 0 : end - history.size();
-
-        if (isForward) {
-            for (int i = start; i < end; i++) {
-                if (history.get(i).toString().contains(searchTerm)) {
-                    idx = i;
-                    break;
-                }
-            }
-        }
-        else {
-            for (int i = end-1; i >= start; i--) {
-                if (history.get(i).toString().contains(searchTerm)) {
-                    idx = i;
-                    break;
-                }
-            }
-        }
-
-        /*
-         * No match? Then restore what we were working on, but make sure
-         * the cursor is at the beginning of the line.
-         */
-        if (idx == -1) {
-            setCursorPosition(0);
-            killLine();
-            putString(origBuffer.buffer);
-            setCursorPosition(0);
-            return -1;
-        }
-
-        /*
-         * Show the match.
-         */
-        setCursorPosition(0);
-        killLine();
-        putString(history.get(idx));
-        setCursorPosition(0);
-        flush();
-
-        /*
-         * While searching really only the "n" and "N" keys are interpreted
-         * as movement, any other key is treated as if you are editing the
-         * line with it, so we return it back up to the caller for interpretation.
-         */
-        isComplete = false;
-        while (!isComplete && (ch = readCharacter()) != -1) {
-            boolean forward = isForward;
-            switch (ch) {
-                case 'p': case 'P':
-                    forward = !isForward;
-                    // Fallthru
-                case 'n': case 'N':
-                    boolean isMatch = false;
-                    if (forward) {
-                        for (int i = idx+1; !isMatch && i < end; i++) {
-                            if (history.get(i).toString().contains(searchTerm)) {
-                                idx = i;
-                                isMatch = true;
-                            }
-                        }
-                    }
-                    else {
-                        for (int i = idx - 1; !isMatch && i >= start; i--) {
-                            if (history.get(i).toString().contains(searchTerm)) {
-                                idx = i;
-                                isMatch = true;
-                            }
-                        }
-                    }
-                    if (isMatch) {
-                        setCursorPosition(0);
-                        killLine();
-                        putString(history.get(idx));
-                        setCursorPosition(0);
-                    }
-                    break;
-                default:
-                    isComplete = true;
-            }
-            flush();
-        }
-
-        /*
-         * Complete?
-         */
-        return ch;
-    }
-
-    public void setParenBlinkTimeout(int timeout) {
-        parenBlinkTimeout = timeout;
-    }
-
-    private void insertClose(String s) throws IOException {
-        putString(s);
-        int closePosition = buf.cursor;
-
-        moveCursor(-1);
-        viMatch();
-
-
-        if (in.isNonBlockingEnabled()) {
-            in.peek(parenBlinkTimeout);
-        }
-
-        setCursorPosition(closePosition);
-        flush();
-    }
-
-    /**
-     * Implements vi style bracket matching ("%" command). The matching
-     * bracket for the current bracket type that you are sitting on is matched.
-     * The logic works like so:
-     * @return true if it worked, false if the cursor was not on a bracket
-     *   character or if there was no matching bracket.
-     */
-    private boolean viMatch() throws IOException {
-        int pos        = buf.cursor;
-
-        if (pos == buf.length()) {
-            return false;
-        }
-
-        int type       = getBracketType(buf.buffer.charAt (pos));
-        int move       = (type < 0) ? -1 : 1;
-        int count      = 1;
-
-        if (type == 0)
-            return false;
-
-        while (count > 0) {
-            pos += move;
-
-            // Fell off the start or end.
-            if (pos < 0 || pos >= buf.buffer.length ()) {
-                return false;
-            }
-
-            int curType = getBracketType(buf.buffer.charAt (pos));
-            if (curType == type) {
-                ++count;
-            }
-            else if (curType == -type) {
-                --count;
-            }
-        }
-
-        /*
-         * Slight adjustment for delete-to, yank-to, change-to to ensure
-         * that the matching paren is consumed
-         */
-        if (move > 0 && isInViMoveOperationState())
-            ++pos;
-
-        setCursorPosition(pos);
-        flush();
-        return true;
-    }
-
-    /**
-     * Given a character determines what type of bracket it is (paren,
-     * square, curly, or none).
-     * @param ch The character to check
-     * @return 1 is square, 2 curly, 3 parent, or zero for none.  The value
-     *   will be negated if it is the closing form of the bracket.
-     */
-    private static int getBracketType (char ch) {
-        switch (ch) {
-            case '[': return  1;
-            case ']': return -1;
-            case '{': return  2;
-            case '}': return -2;
-            case '(': return  3;
-            case ')': return -3;
-            default:
-                return 0;
-        }
-    }
-
-    private boolean deletePreviousWord() throws IOException {
-        StringBuilder killed = new StringBuilder();
-        char c;
-
-        while (isDelimiter((c = buf.current()))) {
-            if (c == 0) {
-                break;
-            }
-
-            killed.append(c);
-            backspace();
-        }
-
-        while (!isDelimiter((c = buf.current()))) {
-            if (c == 0) {
-                break;
-            }
-
-            killed.append(c);
-            backspace();
-        }
-
-        String copy = killed.reverse().toString();
-        killRing.addBackwards(copy);
-        return true;
-    }
-
-    private boolean deleteNextWord() throws IOException {
-        StringBuilder killed = new StringBuilder();
-        char c;
-
-        while (isDelimiter((c = buf.nextChar()))) {
-            if (c == 0) {
-                break;
-            }
-            killed.append(c);
-            delete();
-        }
-
-        while (!isDelimiter((c = buf.nextChar()))) {
-            if (c == 0) {
-                break;
-            }
-            killed.append(c);
-            delete();
-        }
-
-        String copy = killed.toString();
-        killRing.add(copy);
-
-        return true;
-    }
-
-    private boolean capitalizeWord() throws IOException {
-        boolean first = true;
-        int i = 1;
-        char c;
-        while (buf.cursor + i  - 1< buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
-            buf.buffer.setCharAt(buf.cursor + i - 1, first ? Character.toUpperCase(c) : Character.toLowerCase(c));
-            first = false;
-            i++;
-        }
-        drawBuffer();
-        moveCursor(i - 1);
-        return true;
-    }
-
-    private boolean upCaseWord() throws IOException {
-        int i = 1;
-        char c;
-        while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
-            buf.buffer.setCharAt(buf.cursor + i - 1, Character.toUpperCase(c));
-            i++;
-        }
-        drawBuffer();
-        moveCursor(i - 1);
-        return true;
-    }
-
-    private boolean downCaseWord() throws IOException {
-        int i = 1;
-        char c;
-        while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
-            buf.buffer.setCharAt(buf.cursor + i - 1, Character.toLowerCase(c));
-            i++;
-        }
-        drawBuffer();
-        moveCursor(i - 1);
-        return true;
-    }
-
-    /**
-     * Performs character transpose. The character prior to the cursor and the
-     * character under the cursor are swapped and the cursor is advanced one
-     * character unless you are already at the end of the line.
-     *
-     * @param count The number of times to perform the transpose
-     * @return true if the operation succeeded, false otherwise (e.g. transpose
-     *   cannot happen at the beginning of the line).
-     */
-    private boolean transposeChars(int count) throws IOException {
-        for (; count > 0; --count) {
-            if (buf.cursor == 0 || buf.cursor == buf.buffer.length()) {
-                return false;
-            }
-
-            int first  = buf.cursor-1;
-            int second = buf.cursor;
-
-            char tmp = buf.buffer.charAt (first);
-            buf.buffer.setCharAt(first, buf.buffer.charAt(second));
-            buf.buffer.setCharAt(second, tmp);
-
-            // This could be done more efficiently by only re-drawing at the end.
-            moveInternal(-1);
-            drawBuffer();
-            moveInternal(2);
-        }
-
-        return true;
-    }
-
-    public boolean isKeyMap(String name) {
-        // Current keymap.
-        KeyMap map = consoleKeys.getKeys();
-        KeyMap mapByName = consoleKeys.getKeyMaps().get(name);
-
-        if (mapByName == null)
-            return false;
-
-        /*
-         * This may not be safe to do, but there doesn't appear to be a
-         * clean way to find this information out.
-         */
-        return map == mapByName;
-    }
-
-
-    /**
-     * The equivalent of hitting &lt;RET&gt;.  The line is considered
-     * complete and is returned.
-     *
-     * @return The completed line of text.
-     */
-    public String accept() throws IOException {
-        moveToEnd();
-        println(); // output newline
-        flush();
-        return finishBuffer();
-    }
-
-    private void abort() throws IOException {
-        beep();
-        buf.clear();
-        println();
-        redrawLine();
-    }
-
-    /**
-     * Move the cursor <i>where</i> characters.
-     *
-     * @param num   If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
-     * @return      The number of spaces we moved
-     */
-    public int moveCursor(final int num) throws IOException {
-        int where = num;
-
-        if ((buf.cursor == 0) && (where <= 0)) {
-            return 0;
-        }
-
-        if ((buf.cursor == buf.buffer.length()) && (where >= 0)) {
-            return 0;
-        }
-
-        if ((buf.cursor + where) < 0) {
-            where = -buf.cursor;
-        }
-        else if ((buf.cursor + where) > buf.buffer.length()) {
-            where = buf.buffer.length() - buf.cursor;
-        }
-
-        moveInternal(where);
-
-        return where;
-    }
-
-    /**
-     * Move the cursor <i>where</i> characters, without checking the current buffer.
-     *
-     * @param where the number of characters to move to the right or left.
-     */
-    private void moveInternal(final int where) throws IOException {
-        // debug ("move cursor " + where + " ("
-        // + buf.cursor + " => " + (buf.cursor + where) + ")");
-        buf.cursor += where;
-
-        int i0;
-        int i1;
-        if (mask == null) {
-            if (where < 0) {
-                i1 = promptLen + wcwidth(buf.buffer, 0, buf.cursor, promptLen);
-                i0 = i1 + wcwidth(buf.buffer, buf.cursor, buf.cursor - where, i1);
-            } else {
-                i0 = promptLen + wcwidth(buf.buffer, 0, buf.cursor - where, promptLen);
-                i1 = i0 + wcwidth(buf.buffer, buf.cursor - where, buf.cursor, i0);
-            }
-        } else if (mask != NULL_MASK) {
-            i1 = promptLen + buf.cursor;
-            i0 = i1 - where;
-        } else {
-            return;
-        }
-        moveCursorFromTo(i0, i1);
-    }
-
-    private void moveCursorFromTo(int i0, int i1) throws IOException {
-        if (i0 == i1) return;
-        int width = getTerminal().getWidth();
-        int l0 = i0 / width;
-        int c0 = i0 % width;
-        int l1 = i1 / width;
-        int c1 = i1 % width;
-        if (l0 == l1 + 1) {
-            if (!tputs("cursor_up")) {
-                tputs("parm_up_cursor", 1);
-            }
-        } else if (l0 > l1) {
-            if (!tputs("parm_up_cursor", l0 - l1)) {
-                for (int i = l1; i < l0; i++) {
-                    tputs("cursor_up");
-                }
-            }
-        } else if (l0 < l1) {
-            tputs("carriage_return");
-            rawPrint('\n', l1 - l0);
-            c0 = 0;
-        }
-        if (c0 == c1 - 1) {
-            tputs("cursor_right");
-        } else if (c0 == c1 + 1) {
-            tputs("cursor_left");
-        } else if (c0 < c1) {
-            if (!tputs("parm_right_cursor", c1 - c0)) {
-                for (int i = c0; i < c1; i++) {
-                    tputs("cursor_right");
-                }
-            }
-        } else if (c0 > c1) {
-            if (!tputs("parm_left_cursor", c0 - c1)) {
-                for (int i = c1; i < c0; i++) {
-                    tputs("cursor_left");
-                }
-            }
-        }
-        cursorOk = true;
-    }
-
-    /**
-     * Read a character from the console.
-     *
-     * @return the character, or -1 if an EOF is received.
-     */
-    public int readCharacter() throws IOException {
-      return readCharacter(false);
-    }
-
-    /**
-     * Read a character from the console.  If boolean parameter is "true", it will check whether the keystroke was an "alt-" key combination, and
-     * if so add 1000 to the value returned.  Better way...?
-     *
-     * @return the character, or -1 if an EOF is received.
-     */
-    public int readCharacter(boolean checkForAltKeyCombo) throws IOException {
-        int c = reader.read();
-        if (c >= 0) {
-            Log.trace("Keystroke: ", c);
-            // clear any echo characters
-            if (terminal.isSupported()) {
-                clearEcho(c);
-            }
-            if (c == ESCAPE && checkForAltKeyCombo && in.peek(escapeTimeout) >= 32) {
-              /* When ESC is encountered and there is a pending
-               * character in the pushback queue, then it seems to be
-               * an Alt-[key] combination.  Is this true, cross-platform?
-               * It's working for me on Debian GNU/Linux at the moment anyway.
-               * I removed the "isNonBlockingEnabled" check, though it was
-               * in the similar code in "readLine(String prompt, final Character mask)" (way down),
-               * as I am not sure / didn't look up what it's about, and things are working so far w/o it.
-               */
-              int next = reader.read();
-              // with research, there's probably a much cleaner way to do this, but, this is now it flags an Alt key combination for now:
-              next = next + 1000;
-              return next;
-            }
-        }
-        return c;
-    }
-
-    /**
-     * Clear the echoed characters for the specified character code.
-     */
-    private int clearEcho(final int c) throws IOException {
-        // if the terminal is not echoing, then ignore
-        if (!terminal.isEchoEnabled()) {
-            return 0;
-        }
-
-        // otherwise, clear
-        int pos = getCursorPosition();
-        int num = wcwidth(c, pos);
-        moveCursorFromTo(pos + num, pos);
-        drawBuffer(num);
-
-        return num;
-    }
-
-    public int readCharacter(final char... allowed) throws IOException {
-      return readCharacter(false, allowed);
-    }
-
-    public int readCharacter(boolean checkForAltKeyCombo, final char... allowed) throws IOException {
-        // if we restrict to a limited set and the current character is not in the set, then try again.
-        char c;
-
-        Arrays.sort(allowed); // always need to sort before binarySearch
-
-        while (Arrays.binarySearch(allowed, c = (char) readCharacter(checkForAltKeyCombo)) < 0) {
-            // nothing
-        }
-
-        return c;
-    }
-
-    /**
-     * Read from the input stream and decode an operation from the key map.
-     *
-     * The input stream will be read character by character until a matching
-     * binding can be found.  Characters that can't possibly be matched to
-     * any binding will be discarded.
-     *
-     * @param keys the KeyMap to use for decoding the input stream
-     * @return the decoded binding or <code>null</code> if the end of
-     *         stream has been reached
-     */
-    public Object readBinding(KeyMap keys) throws IOException {
-        Object o;
-        opBuffer.setLength(0);
-        do {
-            int c = pushBackChar.isEmpty() ? readCharacter() : pushBackChar.pop();
-            if (c == -1) {
-                return null;
-            }
-            opBuffer.appendCodePoint(c);
-
-            if (recording) {
-                macro += new String(Character.toChars(c));
-            }
-
-            if (quotedInsert) {
-                o = Operation.SELF_INSERT;
-                quotedInsert = false;
-            } else {
-                o = keys.getBound(opBuffer);
-            }
-
-            /*
-             * The kill ring keeps record of whether or not the
-             * previous command was a yank or a kill. We reset
-             * that state here if needed.
-             */
-            if (!recording && !(o instanceof KeyMap)) {
-                if (o != Operation.YANK_POP && o != Operation.YANK) {
-                    killRing.resetLastYank();
-                }
-                if (o != Operation.KILL_LINE && o != Operation.KILL_WHOLE_LINE
-                        && o != Operation.BACKWARD_KILL_WORD && o != Operation.KILL_WORD
-                        && o != Operation.UNIX_LINE_DISCARD && o != Operation.UNIX_WORD_RUBOUT) {
-                    killRing.resetLastKill();
-                }
-            }
-
-            if (o == Operation.DO_LOWERCASE_VERSION) {
-                opBuffer.setLength(opBuffer.length() - 1);
-                opBuffer.append(Character.toLowerCase((char) c));
-                o = keys.getBound(opBuffer);
-            }
-
-            /*
-             * A KeyMap indicates that the key that was struck has a
-             * number of keys that can follow it as indicated in the
-             * map. This is used primarily for Emacs style ESC-META-x
-             * lookups. Since more keys must follow, go back to waiting
-             * for the next key.
-             */
-            if (o instanceof KeyMap) {
-                /*
-                 * The ESC key (#27) is special in that it is ambiguous until
-                 * you know what is coming next.  The ESC could be a literal
-                 * escape, like the user entering vi-move mode, or it could
-                 * be part of a terminal control sequence.  The following
-                 * logic attempts to disambiguate things in the same
-                 * fashion as regular vi or readline.
-                 *
-                 * When ESC is encountered and there is no other pending
-                 * character in the pushback queue, then attempt to peek
-                 * into the input stream (if the feature is enabled) for
-                 * 150ms. If nothing else is coming, then assume it is
-                 * not a terminal control sequence, but a raw escape.
-                 */
-                if (c == ESCAPE
-                        && pushBackChar.isEmpty()
-                        && in.isNonBlockingEnabled()
-                        && in.peek(escapeTimeout) == READ_EXPIRED) {
-                    o = ((KeyMap) o).getAnotherKey();
-                    if (o == null || o instanceof KeyMap) {
-                        continue;
-                    }
-                    opBuffer.setLength(0);
-                } else {
-                    continue;
-                }
-            }
-
-            /*
-             * If we didn't find a binding for the key and there is
-             * more than one character accumulated then start checking
-             * the largest span of characters from the beginning to
-             * see if there is a binding for them.
-             *
-             * For example if our buffer has ESC,CTRL-M,C the getBound()
-             * called previously indicated that there is no binding for
-             * this sequence, so this then checks ESC,CTRL-M, and failing
-             * that, just ESC. Each keystroke that is pealed off the end
-             * during these tests is stuffed onto the pushback buffer so
-             * they won't be lost.
-             *
-             * If there is no binding found, then we go back to waiting for
-             * input.
-             */
-            while (o == null && opBuffer.length() > 0) {
-                c = opBuffer.charAt(opBuffer.length() - 1);
-                opBuffer.setLength(opBuffer.length() - 1);
-                Object o2 = keys.getBound(opBuffer);
-                if (o2 instanceof KeyMap) {
-                    o = ((KeyMap) o2).getAnotherKey();
-                    if (o == null) {
-                        continue;
-                    } else {
-                        pushBackChar.push((char) c);
-                    }
-                }
-            }
-
-        } while (o == null || o instanceof KeyMap);
-
-        return o;
-    }
-
-    public String getLastBinding() {
-        return opBuffer.toString();
-    }
-
-    //
-    // Key Bindings
-    //
-
-    public static final String JLINE_COMPLETION_THRESHOLD = "jline.completion.threshold";
-
-    //
-    // Line Reading
-    //
-
-    /**
-     * Read the next line and return the contents of the buffer.
-     */
-    public String readLine() throws IOException {
-        return readLine((String) null);
-    }
-
-    /**
-     * Read the next line with the specified character mask. If null, then
-     * characters will be echoed. If 0, then no characters will be echoed.
-     */
-    public String readLine(final Character mask) throws IOException {
-        return readLine(null, mask);
-    }
-
-    public String readLine(final String prompt) throws IOException {
-        return readLine(prompt, null);
-    }
-
-    /**
-     * Read a line from the <i>in</i> {@link InputStream}, and return the line
-     * (without any trailing newlines).
-     *
-     * @param prompt    The prompt to issue to the console, may be null.
-     * @return          A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
-     *                  was pressed).
-     */
-    public String readLine(String prompt, final Character mask) throws IOException {
-        return readLine(prompt, mask, null);
-    }
-
-    /**
-     * Sets the current keymap by name. Supported keymaps are "emacs",
-     * "vi-insert", "vi-move".
-     * @param name The name of the keymap to switch to
-     * @return true if the keymap was set, or false if the keymap is
-     *    not recognized.
-     */
-    public boolean setKeyMap(String name) {
-        return consoleKeys.setKeyMap(name);
-    }
-
-    /**
-     * Returns the name of the current key mapping.
-     * @return the name of the key mapping. This will be the canonical name
-     *   of the current mode of the key map and may not reflect the name that
-     *   was used with {@link #setKeyMap(String)}.
-     */
-    public String getKeyMap() {
-        return consoleKeys.getKeys().getName();
-    }
-
-    /**
-     * Read a line from the <i>in</i> {@link InputStream}, and return the line
-     * (without any trailing newlines).
-     *
-     * @param prompt    The prompt to issue to the console, may be null.
-     * @return          A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
-     *                  was pressed).
-     */
-    public String readLine(String prompt, final Character mask, String buffer) throws IOException {
-        // prompt may be null
-        // mask may be null
-        // buffer may be null
-
-        /*
-         * This is the accumulator for VI-mode repeat count. That is, while in
-         * move mode, if you type 30x it will delete 30 characters. This is
-         * where the "30" is accumulated until the command is struck.
-         */
-        int repeatCount = 0;
-
-        // FIXME: This blows, each call to readLine will reset the console's state which doesn't seem very nice.
-        this.mask = mask != null ? mask : this.echoCharacter;
-        if (prompt != null) {
-            setPrompt(prompt);
-        }
-        else {
-            prompt = getPrompt();
-        }
-
-        try {
-            if (buffer != null) {
-                buf.write(buffer);
-            }
-
-            if (!terminal.isSupported()) {
-                beforeReadLine(prompt, mask);
-            }
-
-            if (buffer != null && buffer.length() > 0
-                    || prompt != null && prompt.length() > 0) {
-                drawLine();
-                out.flush();
-            }
-
-            if (terminal.isAnsiSupported() && System.console() != null) {
-                //detect the prompt length by reading the cursor position from the terminal
-                //the real prompt length could differ from the simple prompt length due to
-                //use of escape sequences:
-                out.write("\033[6n");
-                out.flush();
-                StringBuilder input = new StringBuilder();
-                while (true) {
-                    int read;
-                    while ((read = in.read()) != 'R') {
-                        input.appendCodePoint(read);
-                    }
-                    input.appendCodePoint(read);
-                    Matcher m = CURSOR_COLUMN_PATTERN.matcher(input);
-                    if (m.matches()) {
-                        promptLen = Integer.parseInt(m.group("column")) - 1;
-                        String prefix = m.group("prefix");
-                        List<Character> chars = new ArrayList<>();
-                        for (int i = prefix.length() - 1; i >= 0; i--) {
-                            chars.add(prefix.charAt(i));
-                        }
-                        pushBackChar.addAll(0, chars);
-                        break;
-                    }
-                }
-            }
-
-            // if the terminal is unsupported, just use plain-java reading
-            if (!terminal.isSupported()) {
-                return readLineSimple();
-            }
-
-            if (handleUserInterrupt) {
-                terminal.disableInterruptCharacter();
-            }
-            if (handleLitteralNext && (terminal instanceof UnixTerminal)) {
-                ((UnixTerminal) terminal).disableLitteralNextCharacter();
-            }
-
-            String originalPrompt = this.prompt;
-
-            state = State.NORMAL;
-
-            boolean success = true;
-
-            while (true) {
-
-                Object o = readBinding(getKeys());
-                if (o == null) {
-                    return null;
-                }
-                int c = 0;
-                if (opBuffer.length() > 0) {
-                    c = opBuffer.codePointBefore(opBuffer.length());
-                }
-                Log.trace("Binding: ", o);
-
-
-                // Handle macros
-                if (o instanceof String) {
-                    String macro = (String) o;
-                    for (int i = 0; i < macro.length(); i++) {
-                        pushBackChar.push(macro.charAt(macro.length() - 1 - i));
-                    }
-                    opBuffer.setLength(0);
-                    continue;
-                }
-
-                // Handle custom callbacks
-                //original code:
-//                if (o instanceof ActionListener) {
-//                    ((ActionListener) o).actionPerformed(null);
-//                    sb.setLength( 0 );
-//                    continue;
-//                }
-                //using reflection to avoid dependency on java.desktop:
-                try {
-                    Class<?> actionListener =
-                            Class.forName("java.awt.event.ActionListener", false, ClassLoader.getSystemClassLoader());
-                    Class<?> actionEvent =
-                            Class.forName("java.awt.event.ActionEvent", false, ClassLoader.getSystemClassLoader());
-                    if (actionListener.isAssignableFrom(o.getClass())) {
-                        Method actionPerformed =
-                                actionListener.getMethod("actionPerformed", actionEvent);
-                        try {
-                            actionPerformed.invoke(o, (Object) null);
-                        } catch (InvocationTargetException ex ) {
-                            Log.error("Exception while running registered action", ex);
-                        }
-                        opBuffer.setLength(0);
-                        continue;
-                    }
-                } catch (ReflectiveOperationException ex) {
-                    //ignore
-                }
-
-                if (o instanceof Runnable) {
-                    ((Runnable) o).run();
-                    opBuffer.setLength(0);
-                    continue;
-                }
-
-                CursorBuffer oldBuf = new CursorBuffer();
-                oldBuf.buffer.append(buf.buffer);
-                oldBuf.cursor = buf.cursor;
-
-                // Search mode.
-                //
-                // Note that we have to do this first, because if there is a command
-                // not linked to a search command, we leave the search mode and fall
-                // through to the normal state.
-                if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
-                    int cursorDest = -1;
-                    // TODO: check the isearch-terminators variable terminating the search
-                    switch ( ((Operation) o )) {
-                        case ABORT:
-                            state = State.NORMAL;
-                            buf.clear();
-                            buf.write(originalBuffer.buffer);
-                            buf.cursor = originalBuffer.cursor;
-                            break;
-
-                        case REVERSE_SEARCH_HISTORY:
-                            state = State.SEARCH;
-                            if (searchTerm.length() == 0) {
-                                searchTerm.append(previousSearchTerm);
-                            }
-
-                            if (searchIndex > 0) {
-                                searchIndex = searchBackwards(searchTerm.toString(), searchIndex);
-                            }
-                            break;
-
-                        case FORWARD_SEARCH_HISTORY:
-                            state = State.FORWARD_SEARCH;
-                            if (searchTerm.length() == 0) {
-                                searchTerm.append(previousSearchTerm);
-                            }
-
-                            if (searchIndex > -1 && searchIndex < history.size() - 1) {
-                                searchIndex = searchForwards(searchTerm.toString(), searchIndex);
-                            }
-                            break;
-
-                        case BACKWARD_DELETE_CHAR:
-                            if (searchTerm.length() > 0) {
-                                searchTerm.deleteCharAt(searchTerm.length() - 1);
-                                if (state == State.SEARCH) {
-                                    searchIndex = searchBackwards(searchTerm.toString());
-                                } else {
-                                    searchIndex = searchForwards(searchTerm.toString());
-                                }
-                            }
-                            break;
-
-                        case SELF_INSERT:
-                            searchTerm.appendCodePoint(c);
-                            if (state == State.SEARCH) {
-                                searchIndex = searchBackwards(searchTerm.toString());
-                            } else {
-                                searchIndex = searchForwards(searchTerm.toString());
-                            }
-                            break;
-
-                        default:
-                            // Set buffer and cursor position to the found string.
-                            if (searchIndex != -1) {
-                                history.moveTo(searchIndex);
-                                // set cursor position to the found string
-                                cursorDest = history.current().toString().indexOf(searchTerm.toString());
-                            }
-                            if (o != Operation.ACCEPT_LINE) {
-                                o = null;
-                            }
-                            state = State.NORMAL;
-                            break;
-                    }
-
-                    // if we're still in search mode, print the search status
-                    if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
-                        if (searchTerm.length() == 0) {
-                            if (state == State.SEARCH) {
-                                printSearchStatus("", "");
-                            } else {
-                                printForwardSearchStatus("", "");
-                            }
-                            searchIndex = -1;
-                        } else {
-                            if (searchIndex == -1) {
-                                beep();
-                                printSearchStatus(searchTerm.toString(), "");
-                            } else if (state == State.SEARCH) {
-                                printSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
-                            } else {
-                                printForwardSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
-                            }
-                        }
-                    }
-                    // otherwise, restore the line
-                    else {
-                        restoreLine(originalPrompt, cursorDest);
-                    }
-                }
-                if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
-                    /*
-                     * If this is still false at the end of the switch, then
-                     * we reset our repeatCount to 0.
-                     */
-                    boolean isArgDigit = false;
-
-                    /*
-                     * Every command that can be repeated a specified number
-                     * of times, needs to know how many times to repeat, so
-                     * we figure that out here.
-                     */
-                    int count = (repeatCount == 0) ? 1 : repeatCount;
-
-                    /*
-                     * Default success to true. You only need to explicitly
-                     * set it if something goes wrong.
-                     */
-                    success = true;
-
-                    if (o instanceof Operation) {
-                        Operation op = (Operation)o;
-                        /*
-                         * Current location of the cursor (prior to the operation).
-                         * These are used by vi *-to operation (e.g. delete-to)
-                         * so we know where we came from.
-                         */
-                        int     cursorStart = buf.cursor;
-                        State   origState   = state;
-
-                        /*
-                         * If we are on a "vi" movement based operation, then we
-                         * need to restrict the sets of inputs pretty heavily.
-                         */
-                        if (state == State.VI_CHANGE_TO
-                            || state == State.VI_YANK_TO
-                            || state == State.VI_DELETE_TO) {
-
-                            op = viDeleteChangeYankToRemap(op);
-                        }
-
-                        switch ( op ) {
-                            case COMPLETE: // tab
-                                // There is an annoyance with tab completion in that
-                                // sometimes the user is actually pasting input in that
-                                // has physical tabs in it.  This attempts to look at how
-                                // quickly a character follows the tab, if the character
-                                // follows *immediately*, we assume it is a tab literal.
-                                boolean isTabLiteral = false;
-                                if (copyPasteDetection
-                                    && c == 9
-                                    && (!pushBackChar.isEmpty()
-                                        || (in.isNonBlockingEnabled() && in.peek(escapeTimeout) != -2))) {
-                                    isTabLiteral = true;
-                                }
-
-                                if (! isTabLiteral) {
-                                    success = complete();
-                                }
-                                else {
-                                    putString(opBuffer);
-                                }
-                                break;
-
-                            case POSSIBLE_COMPLETIONS:
-                                printCompletionCandidates();
-                                break;
-
-                            case BEGINNING_OF_LINE:
-                                success = setCursorPosition(0);
-                                break;
-
-                            case YANK:
-                                success = yank();
-                                break;
-
-                            case YANK_POP:
-                                success = yankPop();
-                                break;
-
-                            case KILL_LINE: // CTRL-K
-                                success = killLine();
-                                break;
-
-                            case KILL_WHOLE_LINE:
-                                success = setCursorPosition(0) && killLine();
-                                break;
-
-                            case CLEAR_SCREEN: // CTRL-L
-                                success = clearScreen();
-                                redrawLine();
-                                break;
-
-                            case OVERWRITE_MODE:
-                                buf.setOverTyping(!buf.isOverTyping());
-                                break;
-
-                            case SELF_INSERT:
-                                putString(opBuffer);
-                                break;
-
-                            case ACCEPT_LINE:
-                                return accept();
-
-                            case ABORT:
-                                if (searchTerm == null) {
-                                    abort();
-                                }
-                                break;
-
-                            case INTERRUPT:
-                                if (handleUserInterrupt) {
-                                    println();
-                                    flush();
-                                    String partialLine = buf.buffer.toString();
-                                    buf.clear();
-                                    history.moveToEnd();
-                                    throw new UserInterruptException(partialLine);
-                                }
-                                break;
-
-                            /*
-                             * VI_MOVE_ACCEPT_LINE is the result of an ENTER
-                             * while in move mode. This is the same as a normal
-                             * ACCEPT_LINE, except that we need to enter
-                             * insert mode as well.
-                             */
-                            case VI_MOVE_ACCEPT_LINE:
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                return accept();
-
-                            case BACKWARD_WORD:
-                                success = previousWord();
-                                break;
-
-                            case FORWARD_WORD:
-                                success = nextWord();
-                                break;
-
-                            case PREVIOUS_HISTORY:
-                                success = moveHistory(false);
-                                break;
-
-                            /*
-                             * According to bash/readline move through history
-                             * in "vi" mode will move the cursor to the
-                             * start of the line. If there is no previous
-                             * history, then the cursor doesn't move.
-                             */
-                            case VI_PREVIOUS_HISTORY:
-                                success = moveHistory(false, count)
-                                    && setCursorPosition(0);
-                                break;
-
-                            case NEXT_HISTORY:
-                                success = moveHistory(true);
-                                break;
-
-                            /*
-                             * According to bash/readline move through history
-                             * in "vi" mode will move the cursor to the
-                             * start of the line. If there is no next history,
-                             * then the cursor doesn't move.
-                             */
-                            case VI_NEXT_HISTORY:
-                                success = moveHistory(true, count)
-                                    && setCursorPosition(0);
-                                break;
-
-                            case BACKWARD_DELETE_CHAR: // backspace
-                                success = backspace();
-                                break;
-
-                            case EXIT_OR_DELETE_CHAR:
-                                if (buf.buffer.length() == 0) {
-                                    return null;
-                                }
-                                success = deleteCurrentCharacter();
-                                break;
-
-                            case DELETE_CHAR: // delete
-                                success = deleteCurrentCharacter();
-                                break;
-
-                            case BACKWARD_CHAR:
-                                success = moveCursor(-(count)) != 0;
-                                break;
-
-                            case FORWARD_CHAR:
-                                success = moveCursor(count) != 0;
-                                break;
-
-                            case UNIX_LINE_DISCARD:
-                                success = resetLine();
-                                break;
-
-                            case UNIX_WORD_RUBOUT:
-                                success = unixWordRubout(count);
-                                break;
-
-                            case BACKWARD_KILL_WORD:
-                                success = deletePreviousWord();
-                                break;
-
-                            case KILL_WORD:
-                                success = deleteNextWord();
-                                break;
-
-                            case BEGINNING_OF_HISTORY:
-                                success = history.moveToFirst();
-                                if (success) {
-                                    setBuffer(history.current());
-                                }
-                                break;
-
-                            case END_OF_HISTORY:
-                                success = history.moveToLast();
-                                if (success) {
-                                    setBuffer(history.current());
-                                }
-                                break;
-
-                            case HISTORY_SEARCH_BACKWARD:
-                                searchTerm = new StringBuffer(buf.upToCursor());
-                                searchIndex = searchBackwards(searchTerm.toString(), history.index(), true);
-
-                                if (searchIndex == -1) {
-                                    beep();
-                                } else {
-                                    // Maintain cursor position while searching.
-                                    success = history.moveTo(searchIndex);
-                                    if (success) {
-                                        setBufferKeepPos(history.current());
-                                    }
-                                }
-                                break;
-
-                            case HISTORY_SEARCH_FORWARD:
-                                searchTerm = new StringBuffer(buf.upToCursor());
-                                int index = history.index() + 1;
-
-                                if (index == history.size()) {
-                                    history.moveToEnd();
-                                    setBufferKeepPos(searchTerm.toString());
-                                } else if (index < history.size()) {
-                                    searchIndex = searchForwards(searchTerm.toString(), index, true);
-                                    if (searchIndex == -1) {
-                                        beep();
-                                    } else {
-                                        // Maintain cursor position while searching.
-                                        success = history.moveTo(searchIndex);
-                                        if (success) {
-                                            setBufferKeepPos(history.current());
-                                        }
-                                    }
-                                }
-                                break;
-
-                            case REVERSE_SEARCH_HISTORY:
-                                originalBuffer = new CursorBuffer();
-                                originalBuffer.write(buf.buffer);
-                                originalBuffer.cursor = buf.cursor;
-                                if (searchTerm != null) {
-                                    previousSearchTerm = searchTerm.toString();
-                                }
-                                searchTerm = new StringBuffer(buf.buffer);
-                                state = State.SEARCH;
-                                if (searchTerm.length() > 0) {
-                                    searchIndex = searchBackwards(searchTerm.toString());
-                                    if (searchIndex == -1) {
-                                        beep();
-                                    }
-                                    printSearchStatus(searchTerm.toString(),
-                                            searchIndex > -1 ? history.get(searchIndex).toString() : "");
-                                } else {
-                                    searchIndex = -1;
-                                    printSearchStatus("", "");
-                                }
-                                break;
-
-                            case FORWARD_SEARCH_HISTORY:
-                                originalBuffer = new CursorBuffer();
-                                originalBuffer.write(buf.buffer);
-                                originalBuffer.cursor = buf.cursor;
-                                if (searchTerm != null) {
-                                    previousSearchTerm = searchTerm.toString();
-                                }
-                                searchTerm = new StringBuffer(buf.buffer);
-                                state = State.FORWARD_SEARCH;
-                                if (searchTerm.length() > 0) {
-                                    searchIndex = searchForwards(searchTerm.toString());
-                                    if (searchIndex == -1) {
-                                        beep();
-                                    }
-                                    printForwardSearchStatus(searchTerm.toString(),
-                                            searchIndex > -1 ? history.get(searchIndex).toString() : "");
-                                } else {
-                                    searchIndex = -1;
-                                    printForwardSearchStatus("", "");
-                                }
-                                break;
-
-                            case CAPITALIZE_WORD:
-                                success = capitalizeWord();
-                                break;
-
-                            case UPCASE_WORD:
-                                success = upCaseWord();
-                                break;
-
-                            case DOWNCASE_WORD:
-                                success = downCaseWord();
-                                break;
-
-                            case END_OF_LINE:
-                                success = moveToEnd();
-                                break;
-
-                            case TAB_INSERT:
-                                putString( "\t" );
-                                break;
-
-                            case RE_READ_INIT_FILE:
-                                consoleKeys.loadKeys(appName, inputrcUrl);
-                                break;
-
-                            case START_KBD_MACRO:
-                                recording = true;
-                                break;
-
-                            case END_KBD_MACRO:
-                                recording = false;
-                                macro = macro.substring(0, macro.length() - opBuffer.length());
-                                break;
-
-                            case CALL_LAST_KBD_MACRO:
-                                for (int i = 0; i < macro.length(); i++) {
-                                    pushBackChar.push(macro.charAt(macro.length() - 1 - i));
-                                }
-                                opBuffer.setLength(0);
-                                break;
-
-                            case VI_EDITING_MODE:
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case VI_MOVEMENT_MODE:
-                                /*
-                                 * If we are re-entering move mode from an
-                                 * aborted yank-to, delete-to, change-to then
-                                 * don't move the cursor back. The cursor is
-                                 * only move on an expclit entry to movement
-                                 * mode.
-                                 */
-                                if (state == State.NORMAL) {
-                                    moveCursor(-1);
-                                }
-                                consoleKeys.setKeyMap(KeyMap.VI_MOVE);
-                                break;
-
-                            case VI_INSERTION_MODE:
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case VI_APPEND_MODE:
-                                moveCursor(1);
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case VI_APPEND_EOL:
-                                success = moveToEnd();
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            /*
-                             * Handler for CTRL-D. Attempts to follow readline
-                             * behavior. If the line is empty, then it is an EOF
-                             * otherwise it is as if the user hit enter.
-                             */
-                            case VI_EOF_MAYBE:
-                                if (buf.buffer.length() == 0) {
-                                    return null;
-                                }
-                                return accept();
-
-                            case TRANSPOSE_CHARS:
-                                success = transposeChars(count);
-                                break;
-
-                            case INSERT_COMMENT:
-                                return insertComment (false);
-
-                            case INSERT_CLOSE_CURLY:
-                                insertClose("}");
-                                break;
-
-                            case INSERT_CLOSE_PAREN:
-                                insertClose(")");
-                                break;
-
-                            case INSERT_CLOSE_SQUARE:
-                                insertClose("]");
-                                break;
-
-                            case VI_INSERT_COMMENT:
-                                return insertComment (true);
-
-                            case VI_MATCH:
-                                success = viMatch ();
-                                break;
-
-                            case VI_SEARCH:
-                                int lastChar = viSearch(opBuffer.charAt(0));
-                                if (lastChar != -1) {
-                                    pushBackChar.push((char)lastChar);
-                                }
-                                break;
-
-                            case VI_ARG_DIGIT:
-                                repeatCount = (repeatCount * 10) + opBuffer.charAt(0) - '0';
-                                isArgDigit = true;
-                                break;
-
-                            case VI_BEGINNING_OF_LINE_OR_ARG_DIGIT:
-                                if (repeatCount > 0) {
-                                    repeatCount = (repeatCount * 10) + opBuffer.charAt(0) - '0';
-                                    isArgDigit = true;
-                                }
-                                else {
-                                    success = setCursorPosition(0);
-                                }
-                                break;
-
-                            case VI_FIRST_PRINT:
-                                success = setCursorPosition(0) && viNextWord(1);
-                                break;
-
-                            case VI_PREV_WORD:
-                                success = viPreviousWord(count);
-                                break;
-
-                            case VI_NEXT_WORD:
-                                success = viNextWord(count);
-                                break;
-
-                            case VI_END_WORD:
-                                success = viEndWord(count);
-                                break;
-
-                            case VI_INSERT_BEG:
-                                success = setCursorPosition(0);
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case VI_RUBOUT:
-                                success = viRubout(count);
-                                break;
-
-                            case VI_DELETE:
-                                success = viDelete(count);
-                                break;
-
-                            case VI_DELETE_TO:
-                                /*
-                                 * This is a weird special case. In vi
-                                 * "dd" deletes the current line. So if we
-                                 * get a delete-to, followed by a delete-to,
-                                 * we delete the line.
-                                 */
-                                if (state == State.VI_DELETE_TO) {
-                                    success = setCursorPosition(0) && killLine();
-                                    state = origState = State.NORMAL;
-                                }
-                                else {
-                                    state = State.VI_DELETE_TO;
-                                }
-                                break;
-
-                            case VI_YANK_TO:
-                                // Similar to delete-to, a "yy" yanks the whole line.
-                                if (state == State.VI_YANK_TO) {
-                                    yankBuffer = buf.buffer.toString();
-                                    state = origState = State.NORMAL;
-                                }
-                                else {
-                                    state = State.VI_YANK_TO;
-                                }
-                                break;
-
-                            case VI_CHANGE_TO:
-                                if (state == State.VI_CHANGE_TO) {
-                                    success = setCursorPosition(0) && killLine();
-                                    state = origState = State.NORMAL;
-                                    consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                }
-                                else {
-                                    state = State.VI_CHANGE_TO;
-                                }
-                                break;
-
-                            case VI_KILL_WHOLE_LINE:
-                                success = setCursorPosition(0) && killLine();
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case VI_PUT:
-                                success = viPut(count);
-                                break;
-
-                            case VI_CHAR_SEARCH: {
-                                 // ';' and ',' don't need another character. They indicate repeat next or repeat prev.
-                                int searchChar = (c != ';' && c != ',')
-                                    ? (pushBackChar.isEmpty()
-                                        ? readCharacter()
-                                        : pushBackChar.pop ())
-                                    : 0;
-
-                                    success = viCharSearch(count, c, searchChar);
-                                }
-                                break;
-
-                            case VI_CHANGE_CASE:
-                                success = viChangeCase(count);
-                                break;
-
-                            case VI_CHANGE_CHAR:
-                                success = viChangeChar(count,
-                                    pushBackChar.isEmpty()
-                                        ? readCharacter()
-                                        : pushBackChar.pop());
-                                break;
-
-                            case VI_DELETE_TO_EOL:
-                                success = viDeleteTo(buf.cursor, buf.buffer.length(), false);
-                                break;
-
-                            case VI_CHANGE_TO_EOL:
-                                success = viDeleteTo(buf.cursor, buf.buffer.length(), true);
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                                break;
-
-                            case EMACS_EDITING_MODE:
-                                consoleKeys.setKeyMap(KeyMap.EMACS);
-                                break;
-
-                            case QUIT:
-                                getCursorBuffer().clear();
-                                return accept();
-
-                            case QUOTED_INSERT:
-                                quotedInsert = true;
-                                break;
-
-                            case PASTE_FROM_CLIPBOARD:
-//                                paste();
-                                break;
-
-                            default:
-                                break;
-                        }
-
-                        /*
-                         * If we were in a yank-to, delete-to, move-to
-                         * when this operation started, then fall back to
-                         */
-                        if (origState != State.NORMAL) {
-                            if (origState == State.VI_DELETE_TO) {
-                                success = viDeleteTo(cursorStart, buf.cursor, false);
-                            }
-                            else if (origState == State.VI_CHANGE_TO) {
-                                success = viDeleteTo(cursorStart, buf.cursor, true);
-                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
-                            }
-                            else if (origState == State.VI_YANK_TO) {
-                                success = viYankTo(cursorStart, buf.cursor);
-                            }
-                            state = State.NORMAL;
-                        }
-
-                        /*
-                         * Another subtly. The check for the NORMAL state is
-                         * to ensure that we do not clear out the repeat
-                         * count when in delete-to, yank-to, or move-to modes.
-                         */
-                        if (state == State.NORMAL && !isArgDigit) {
-                            /*
-                             * If the operation performed wasn't a vi argument
-                             * digit, then clear out the current repeatCount;
-                             */
-                            repeatCount = 0;
-                        }
-
-                        if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
-                            originalBuffer = null;
-                            previousSearchTerm = "";
-                            searchTerm = null;
-                            searchIndex = -1;
-                        }
-                    }
-                }
-                if (!success) {
-                    beep();
-                }
-                opBuffer.setLength(0);
-
-                flush();
-            }
-        }
-        finally {
-            if (!terminal.isSupported()) {
-                afterReadLine();
-            }
-            if (handleUserInterrupt) {
-                terminal.enableInterruptCharacter();
-            }
-        }
-    }
-    //where:
-        private Pattern CURSOR_COLUMN_PATTERN =
-                Pattern.compile("(?<prefix>.*)\033\\[[0-9]+;(?<column>[0-9]+)R", Pattern.DOTALL);
-
-    /**
-     * Read a line for unsupported terminals.
-     */
-    private String readLineSimple() throws IOException {
-
-        if (skipLF) {
-            skipLF = false;
-
-            int i = readCharacter();
-
-            if (i == -1 || i == '\r') {
-                return finishBuffer();
-            } else if (i == '\n') {
-                // ignore
-            } else {
-                buf.buffer.append((char) i);
-            }
-        }
-
-        while (true) {
-            int i = readCharacter();
-
-            if (i == -1 && buf.buffer.length() == 0) {
-              return null;
-            }
-
-            if (i == -1 || i == '\n') {
-                return finishBuffer();
-            } else if (i == '\r') {
-                skipLF = true;
-                return finishBuffer();
-            } else {
-                buf.buffer.append((char) i);
-            }
-        }
-    }
-
-    //
-    // Completion
-    //
-
-    private final List<Completer> completers = new LinkedList<Completer>();
-
-    private CompletionHandler completionHandler = new CandidateListCompletionHandler();
-
-    /**
-     * Add the specified {@link jline.console.completer.Completer} to the list of handlers for tab-completion.
-     *
-     * @param completer the {@link jline.console.completer.Completer} to add
-     * @return true if it was successfully added
-     */
-    public boolean addCompleter(final Completer completer) {
-        return completers.add(completer);
-    }
-
-    /**
-     * Remove the specified {@link jline.console.completer.Completer} from the list of handlers for tab-completion.
-     *
-     * @param completer     The {@link Completer} to remove
-     * @return              True if it was successfully removed
-     */
-    public boolean removeCompleter(final Completer completer) {
-        return completers.remove(completer);
-    }
-
-    /**
-     * Returns an unmodifiable list of all the completers.
-     */
-    public Collection<Completer> getCompleters() {
-        return Collections.unmodifiableList(completers);
-    }
-
-    public void setCompletionHandler(final CompletionHandler handler) {
-        this.completionHandler = checkNotNull(handler);
-    }
-
-    public CompletionHandler getCompletionHandler() {
-        return this.completionHandler;
-    }
-
-    /**
-     * Use the completers to modify the buffer with the appropriate completions.
-     *
-     * @return true if successful
-     */
-    protected boolean complete() throws IOException {
-        // debug ("tab for (" + buf + ")");
-        if (completers.size() == 0) {
-            return false;
-        }
-
-        List<CharSequence> candidates = new LinkedList<CharSequence>();
-        String bufstr = buf.buffer.toString();
-        int cursor = buf.cursor;
-
-        int position = -1;
-
-        for (Completer comp : completers) {
-            if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
-                break;
-            }
-        }
-
-        return candidates.size() != 0 && getCompletionHandler().complete(this, candidates, position);
-    }
-
-    protected void printCompletionCandidates() throws IOException {
-        // debug ("tab for (" + buf + ")");
-        if (completers.size() == 0) {
-            return;
-        }
-
-        List<CharSequence> candidates = new LinkedList<CharSequence>();
-        String bufstr = buf.buffer.toString();
-        int cursor = buf.cursor;
-
-        for (Completer comp : completers) {
-            if (comp.complete(bufstr, cursor, candidates) != -1) {
-                break;
-            }
-        }
-        CandidateListCompletionHandler.printCandidates(this, candidates);
-        drawLine();
-    }
-
-    /**
-     * The number of tab-completion candidates above which a warning will be
-     * prompted before showing all the candidates.
-     */
-    private int autoprintThreshold = Configuration.getInteger(JLINE_COMPLETION_THRESHOLD, 100); // same default as bash
-
-    /**
-     * @param threshold the number of candidates to print without issuing a warning.
-     */
-    public void setAutoprintThreshold(final int threshold) {
-        this.autoprintThreshold = threshold;
-    }
-
-    /**
-     * @return the number of candidates to print without issuing a warning.
-     */
-    public int getAutoprintThreshold() {
-        return autoprintThreshold;
-    }
-
-    private boolean paginationEnabled;
-
-    /**
-     * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
-     */
-    public void setPaginationEnabled(final boolean enabled) {
-        this.paginationEnabled = enabled;
-    }
-
-    /**
-     * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
-     */
-    public boolean isPaginationEnabled() {
-        return paginationEnabled;
-    }
-
-    //
-    // History
-    //
-
-    private History history = new MemoryHistory();
-
-    public void setHistory(final History history) {
-        this.history = history;
-    }
-
-    public History getHistory() {
-        return history;
-    }
-
-    private boolean historyEnabled = true;
-
-    /**
-     * Whether or not to add new commands to the history buffer.
-     */
-    public void setHistoryEnabled(final boolean enabled) {
-        this.historyEnabled = enabled;
-    }
-
-    /**
-     * Whether or not to add new commands to the history buffer.
-     */
-    public boolean isHistoryEnabled() {
-        return historyEnabled;
-    }
-
-    /**
-     * Used in "vi" mode for argumented history move, to move a specific
-     * number of history entries forward or back.
-     *
-     * @param next If true, move forward
-     * @param count The number of entries to move
-     * @return true if the move was successful
-     */
-    private boolean moveHistory(final boolean next, int count) throws IOException {
-        boolean ok = true;
-        for (int i = 0; i < count && (ok = moveHistory(next)); i++) {
-            /* empty */
-        }
-        return ok;
-    }
-
-    /**
-     * Move up or down the history tree.
-     */
-    private boolean moveHistory(final boolean next) throws IOException {
-        if (next && !history.next()) {
-            return false;
-        }
-        else if (!next && !history.previous()) {
-            return false;
-        }
-
-        setBuffer(history.current());
-
-        return true;
-    }
-
-    //
-    // Printing
-    //
-
-    /**
-     * Output the specified characters to the output stream without manipulating the current buffer.
-     */
-    private int fmtPrint(final CharSequence buff, int cursorPos) throws IOException {
-        return fmtPrint(buff, 0, buff.length(), cursorPos);
-    }
-
-    private int fmtPrint(final CharSequence buff, int start, int end) throws IOException {
-        return fmtPrint(buff, start, end, getCursorPosition());
-    }
-
-    private int fmtPrint(final CharSequence buff, int start, int end, int cursorPos) throws IOException {
-        checkNotNull(buff);
-        for (int i = start; i < end; i++) {
-            char c = buff.charAt(i);
-            if (c == '\t') {
-                int nb = nextTabStop(cursorPos);
-                cursorPos += nb;
-                while (nb-- > 0) {
-                    out.write(' ');
-                }
-            } else if (c < 32) {
-                out.write('^');
-                out.write((char) (c + '@'));
-                cursorPos += 2;
-            } else {
-                int w = WCWidth.wcwidth(c);
-                if (w > 0) {
-                    out.write(c);
-                    cursorPos += w;
-                }
-            }
-        }
-        cursorOk = false;
-        return cursorPos;
-    }
-
-    /**
-     * Output the specified string to the output stream (but not the buffer).
-     */
-    public void print(final CharSequence s) throws IOException {
-        rawPrint(s.toString());
-    }
-
-    public void println(final CharSequence s) throws IOException {
-        print(s);
-        println();
-    }
-
-    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
-
-    /**
-     * Output a platform-dependent newline.
-     */
-    public void println() throws IOException {
-        rawPrint(LINE_SEPARATOR);
-    }
-
-    /**
-     * Raw output printing
-     */
-    final void rawPrint(final int c) throws IOException {
-        out.write(c);
-        cursorOk = false;
-    }
-
-    final void rawPrint(final String str) throws IOException {
-        out.write(str);
-        cursorOk = false;
-    }
-
-    private void rawPrint(final char c, final int num) throws IOException {
-        for (int i = 0; i < num; i++) {
-            rawPrint(c);
-        }
-    }
-
-    private void rawPrintln(final String s) throws IOException {
-        rawPrint(s);
-        println();
-    }
-
-
-    //
-    // Actions
-    //
-
-    /**
-     * Issue a delete.
-     *
-     * @return true if successful
-     */
-    public boolean delete() throws IOException {
-        if (buf.cursor == buf.buffer.length()) {
-          return false;
-        }
-
-        buf.buffer.delete(buf.cursor, buf.cursor + 1);
-        drawBuffer(1);
-
-        return true;
-    }
-
-    /**
-     * Kill the buffer ahead of the current cursor position.
-     *
-     * @return true if successful
-     */
-    public boolean killLine() throws IOException {
-        int cp = buf.cursor;
-        int len = buf.buffer.length();
-
-        if (cp >= len) {
-            return false;
-        }
-
-        int num = len - cp;
-        int pos = getCursorPosition();
-        int width = wcwidth(buf.buffer, cp, len, pos);
-        clearAhead(width, pos);
-
-        char[] killed = new char[num];
-        buf.buffer.getChars(cp, (cp + num), killed, 0);
-        buf.buffer.delete(cp, (cp + num));
-
-        String copy = new String(killed);
-        killRing.add(copy);
-
-        return true;
-    }
-
-    public boolean yank() throws IOException {
-        String yanked = killRing.yank();
-
-        if (yanked == null) {
-            return false;
-        }
-        putString(yanked);
-        return true;
-    }
-
-    public boolean yankPop() throws IOException {
-        if (!killRing.lastYank()) {
-            return false;
-        }
-        String current = killRing.yank();
-        if (current == null) {
-            // This shouldn't happen.
-            return false;
-        }
-        backspace(current.length());
-        String yanked = killRing.yankPop();
-        if (yanked == null) {
-            // This shouldn't happen.
-            return false;
-        }
-
-        putString(yanked);
-        return true;
-    }
-
-    /**
-     * Clear the screen by issuing the ANSI "clear screen" code.
-     */
-    public boolean clearScreen() throws IOException {
-        if (!tputs("clear_screen")) {
-            println();
-        }
-        return true;
-    }
-
-    /**
-     * Issue an audible keyboard bell.
-     */
-    public void beep() throws IOException {
-        if (bellEnabled) {
-            if (tputs("bell")) {
-                // need to flush so the console actually beeps
-                flush();
-            }
-        }
-    }
-
-    //disabled to avoid dependency on java.desktop:
-//    /**
-//     * Paste the contents of the clipboard into the console buffer
-//     *
-//     * @return true if clipboard contents pasted
-//     */
-//    public boolean paste() throws IOException {
-//        Clipboard clipboard;
-//        try { // May throw ugly exception on system without X
-//            clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
-//        }
-//        catch (Exception e) {
-//            return false;
-//        }
-//
-//        if (clipboard == null) {
-//            return false;
-//        }
-//
-//        Transferable transferable = clipboard.getContents(null);
-//
-//        if (transferable == null) {
-//            return false;
-//        }
-//
-//        try {
-//            @SuppressWarnings("deprecation")
-//            Object content = transferable.getTransferData(DataFlavor.plainTextFlavor);
-//
-//            // This fix was suggested in bug #1060649 at
-//            // http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
-//            // to get around the deprecated DataFlavor.plainTextFlavor, but it
-//            // raises a UnsupportedFlavorException on Mac OS X
-//
-//            if (content == null) {
-//                try {
-//                    content = new DataFlavor().getReaderForText(transferable);
-//                }
-//                catch (Exception e) {
-//                    // ignore
-//                }
-//            }
-//
-//            if (content == null) {
-//                return false;
-//            }
-//
-//            String value;
-//
-//            if (content instanceof Reader) {
-//                // TODO: we might want instead connect to the input stream
-//                // so we can interpret individual lines
-//                value = "";
-//                String line;
-//
-//                BufferedReader read = new BufferedReader((Reader) content);
-//                while ((line = read.readLine()) != null) {
-//                    if (value.length() > 0) {
-//                        value += "\n";
-//                    }
-//
-//                    value += line;
-//                }
-//            }
-//            else {
-//                value = content.toString();
-//            }
-//
-//            if (value == null) {
-//                return true;
-//            }
-//
-//            putString(value);
-//
-//            return true;
-//        }
-//        catch (UnsupportedFlavorException e) {
-//            Log.error("Paste failed: ", e);
-//
-//            return false;
-//        }
-//    }
-
-    //disabled to avoid dependency on java.desktop:
-//    /**
-//     * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
-//     * <p/>
-//     * Say you want to close the application if the user enter q.
-//     * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
-//     */
-//    public void addTriggeredAction(final char c, final ActionListener listener) {
-//        getKeys().bind(Character.toString(c), listener);
-//    }
-
-    //
-    // Formatted Output
-    //
-
-    /**
-     * Output the specified {@link Collection} in proper columns.
-     */
-    public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
-        if (items == null || items.isEmpty()) {
-            return;
-        }
-
-        int width = getTerminal().getWidth();
-        int height = getTerminal().getHeight();
-
-        int maxWidth = 0;
-        for (CharSequence item : items) {
-            // we use 0 here, as we don't really support tabulations inside candidates
-            int len = wcwidth(Ansi.stripAnsi(item.toString()), 0);
-            maxWidth = Math.max(maxWidth, len);
-        }
-        maxWidth = maxWidth + 3;
-        Log.debug("Max width: ", maxWidth);
-
-        int showLines;
-        if (isPaginationEnabled()) {
-            showLines = height - 1; // page limit
-        }
-        else {
-            showLines = Integer.MAX_VALUE;
-        }
-
-        StringBuilder buff = new StringBuilder();
-        int realLength = 0;
-        for (CharSequence item : items) {
-            if ((realLength + maxWidth) > width) {
-                rawPrintln(buff.toString());
-                buff.setLength(0);
-                realLength = 0;
-
-                if (--showLines == 0) {
-                    // Overflow
-                    print(resources.getString("DISPLAY_MORE"));
-                    flush();
-                    int c = readCharacter();
-                    if (c == '\r' || c == '\n') {
-                        // one step forward
-                        showLines = 1;
-                    }
-                    else if (c != 'q') {
-                        // page forward
-                        showLines = height - 1;
-                    }
-
-                    tputs("carriage_return");
-                    if (c == 'q') {
-                        // cancel
-                        break;
-                    }
-                }
-            }
-
-            // NOTE: toString() is important here due to AnsiString being retarded
-            buff.append(item.toString());
-            int strippedItemLength = wcwidth(Ansi.stripAnsi(item.toString()), 0);
-            for (int i = 0; i < (maxWidth - strippedItemLength); i++) {
-                buff.append(' ');
-            }
-            realLength += maxWidth;
-        }
-
-        if (buff.length() > 0) {
-            rawPrintln(buff.toString());
-        }
-    }
-
-    //
-    // Non-supported Terminal Support
-    //
-
-    private Thread maskThread;
-
-    private void beforeReadLine(final String prompt, final Character mask) {
-        if (mask != null && maskThread == null) {
-            final String fullPrompt = "\r" + prompt
-                + "                 "
-                + "                 "
-                + "                 "
-                + "\r" + prompt;
-
-            maskThread = new Thread()
-            {
-                public void run() {
-                    while (!interrupted()) {
-                        try {
-                            Writer out = getOutput();
-                            out.write(fullPrompt);
-                            out.flush();
-                            sleep(3);
-                        }
-                        catch (IOException e) {
-                            return;
-                        }
-                        catch (InterruptedException e) {
-                            return;
-                        }
-                    }
-                }
-            };
-
-            maskThread.setPriority(Thread.MAX_PRIORITY);
-            maskThread.setDaemon(true);
-            maskThread.start();
-        }
-    }
-
-    private void afterReadLine() {
-        if (maskThread != null && maskThread.isAlive()) {
-            maskThread.interrupt();
-        }
-
-        maskThread = null;
-    }
-
-    /**
-     * Erases the current line with the existing prompt, then redraws the line
-     * with the provided prompt and buffer
-     * @param prompt
-     *            the new prompt
-     * @param buffer
-     *            the buffer to be drawn
-     * @param cursorDest
-     *            where you want the cursor set when the line has been drawn.
-     *            -1 for end of line.
-     * */
-    public void resetPromptLine(String prompt, String buffer, int cursorDest) throws IOException {
-        // move cursor to end of line
-        moveToEnd();
-
-        // backspace all text, including prompt
-        buf.buffer.append(this.prompt);
-        int promptLength = 0;
-        if (this.prompt != null) {
-            promptLength = this.prompt.length();
-        }
-
-        buf.cursor += promptLength;
-        setPrompt("");
-        backspaceAll();
-
-        setPrompt(prompt);
-        redrawLine();
-        setBuffer(buffer);
-
-        // move cursor to destination (-1 will move to end of line)
-        if (cursorDest < 0) cursorDest = buffer.length();
-        setCursorPosition(cursorDest);
-
-        flush();
-    }
-
-    public void printSearchStatus(String searchTerm, String match) throws IOException {
-        printSearchStatus(searchTerm, match, "(reverse-i-search)`");
-    }
-
-    public void printForwardSearchStatus(String searchTerm, String match) throws IOException {
-        printSearchStatus(searchTerm, match, "(i-search)`");
-    }
-
-    private void printSearchStatus(String searchTerm, String match, String searchLabel) throws IOException {
-        String prompt = searchLabel + searchTerm + "': ";
-        int cursorDest = match.indexOf(searchTerm);
-        resetPromptLine(prompt, match, cursorDest);
-    }
-
-    public void restoreLine(String originalPrompt, int cursorDest) throws IOException {
-        // TODO move cursor to matched string
-        String prompt = lastLine(originalPrompt);
-        String buffer = buf.buffer.toString();
-        resetPromptLine(prompt, buffer, cursorDest);
-    }
-
-    //
-    // History search
-    //
-    /**
-     * Search backward in history from a given position.
-     *
-     * @param searchTerm substring to search for.
-     * @param startIndex the index from which on to search
-     * @return index where this substring has been found, or -1 else.
-     */
-    public int searchBackwards(String searchTerm, int startIndex) {
-        return searchBackwards(searchTerm, startIndex, false);
-    }
-
-    /**
-     * Search backwards in history from the current position.
-     *
-     * @param searchTerm substring to search for.
-     * @return index where the substring has been found, or -1 else.
-     */
-    public int searchBackwards(String searchTerm) {
-        return searchBackwards(searchTerm, history.index());
-    }
-
-
-    public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
-        ListIterator<History.Entry> it = history.entries(startIndex);
-        while (it.hasPrevious()) {
-            History.Entry e = it.previous();
-            if (startsWith) {
-                if (e.value().toString().startsWith(searchTerm)) {
-                    return e.index();
-                }
-            } else {
-                if (e.value().toString().contains(searchTerm)) {
-                    return e.index();
-                }
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Search forward in history from a given position.
-     *
-     * @param searchTerm substring to search for.
-     * @param startIndex the index from which on to search
-     * @return index where this substring has been found, or -1 else.
-     */
-    public int searchForwards(String searchTerm, int startIndex) {
-        return searchForwards(searchTerm, startIndex, false);
-    }
-    /**
-     * Search forwards in history from the current position.
-     *
-     * @param searchTerm substring to search for.
-     * @return index where the substring has been found, or -1 else.
-     */
-    public int searchForwards(String searchTerm) {
-        return searchForwards(searchTerm, history.index());
-    }
-
-    public int searchForwards(String searchTerm, int startIndex, boolean startsWith) {
-        if (startIndex >= history.size()) {
-            startIndex = history.size() - 1;
-        }
-
-        ListIterator<History.Entry> it = history.entries(startIndex);
-
-        if (searchIndex != -1 && it.hasNext()) {
-            it.next();
-        }
-
-        while (it.hasNext()) {
-            History.Entry e = it.next();
-            if (startsWith) {
-                if (e.value().toString().startsWith(searchTerm)) {
-                    return e.index();
-                }
-            } else {
-                if (e.value().toString().contains(searchTerm)) {
-                    return e.index();
-                }
-            }
-        }
-        return -1;
-    }
-
-    //
-    // Helpers
-    //
-
-    /**
-     * Checks to see if the specified character is a delimiter. We consider a
-     * character a delimiter if it is anything but a letter or digit.
-     *
-     * @param c     The character to test
-     * @return      True if it is a delimiter
-     */
-    private static boolean isDelimiter(final char c) {
-        return !Character.isLetterOrDigit(c);
-    }
-
-    /**
-     * Checks to see if a character is a whitespace character. Currently
-     * this delegates to {@link Character#isWhitespace(char)}, however
-     * eventually it should be hooked up so that the definition of whitespace
-     * can be configured, as readline does.
-     *
-     * @param c The character to check
-     * @return true if the character is a whitespace
-     */
-    private static boolean isWhitespace(final char c) {
-        return Character.isWhitespace (c);
-    }
-
-    private boolean tputs(String cap, Object... params) throws IOException {
-        String str = terminal.getStringCapability(cap);
-        if (str == null) {
-            return false;
-        }
-        Curses.tputs(out, str, params);
-        return true;
-    }
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * A holder for a {@link StringBuilder} that also contains the current cursor position.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class CursorBuffer
-{
-    private boolean overTyping = false;
-
-    public int cursor = 0;
-
-    public final StringBuilder buffer = new StringBuilder();
-
-    public CursorBuffer copy () {
-        CursorBuffer that = new CursorBuffer();
-        that.overTyping = this.overTyping;
-        that.cursor = this.cursor;
-        that.buffer.append (this.toString());
-
-        return that;
-    }
-
-    public boolean isOverTyping() {
-        return overTyping;
-    }
-
-    public void setOverTyping(final boolean b) {
-        overTyping = b;
-    }
-
-    public int length() {
-        return buffer.length();
-    }
-
-    public char nextChar() {
-        if (cursor == buffer.length()) {
-            return 0;
-        } else {
-            return buffer.charAt(cursor);
-        }
-    }
-
-    public char current() {
-        if (cursor <= 0) {
-            return 0;
-        }
-
-        return buffer.charAt(cursor - 1);
-    }
-
-    /**
-     * Write the specific character into the buffer, setting the cursor position
-     * ahead one. The text may overwrite or insert based on the current setting
-     * of {@link #isOverTyping}.
-     *
-     * @param c the character to insert
-     */
-    public void write(final char c) {
-        buffer.insert(cursor++, c);
-        if (isOverTyping() && cursor < buffer.length()) {
-            buffer.deleteCharAt(cursor);
-        }
-    }
-
-    /**
-     * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
-     */
-    public void write(final CharSequence str) {
-        checkNotNull(str);
-
-        if (buffer.length() == 0) {
-            buffer.append(str);
-        }
-        else {
-            buffer.insert(cursor, str);
-        }
-
-        cursor += str.length();
-
-        if (isOverTyping() && cursor < buffer.length()) {
-            buffer.delete(cursor, cursor + str.length());
-        }
-    }
-
-    public boolean clear() {
-        if (buffer.length() == 0) {
-            return false;
-        }
-
-        buffer.delete(0, buffer.length());
-        cursor = 0;
-        return true;
-    }
-
-    public String upToCursor() {
-        if (cursor <= 0) {
-            return "";
-        }
-
-        return buffer.substring(0, cursor);
-    }
-
-    @Override
-    public String toString() {
-        return buffer.toString();
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,577 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * The KeyMap class contains all bindings from keys to operations.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.6
- */
-public class KeyMap {
-
-    public static final String VI_MOVE        = "vi-move";
-    public static final String VI_INSERT      = "vi-insert";
-    public static final String EMACS          = "emacs";
-    public static final String EMACS_STANDARD = "emacs-standard";
-    public static final String EMACS_CTLX     = "emacs-ctlx";
-    public static final String EMACS_META     = "emacs-meta";
-
-    private static final int KEYMAP_LENGTH = 256;
-
-    private static final Object NULL_FUNCTION = new Object();
-
-    private Object[] mapping = new Object[KEYMAP_LENGTH];
-    private Object anotherKey = null;
-    private String name;
-
-    public KeyMap(String name) {
-        this(name, new Object[KEYMAP_LENGTH]);
-    }
-
-    @Deprecated
-    public KeyMap(String name, boolean unused) {
-        this(name);
-    }
-
-    protected KeyMap(String name, Object[] mapping) {
-        this.mapping = mapping;
-        this.name = name;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public Object getAnotherKey() {
-        return anotherKey;
-    }
-
-    public void from(KeyMap other) {
-        this.mapping = other.mapping;
-        this.anotherKey = other.anotherKey;
-    }
-
-    public Object getBound( CharSequence keySeq ) {
-        if (keySeq != null && keySeq.length() > 0) {
-            KeyMap map = this;
-            for (int i = 0; i < keySeq.length(); i++) {
-                char c = keySeq.charAt(i);
-                if (c > 255) {
-                    return Operation.SELF_INSERT;
-                }
-                if (map.mapping[c] instanceof KeyMap) {
-                    if (i == keySeq.length() - 1) {
-                        return map.mapping[c];
-                    } else {
-                        map = (KeyMap) map.mapping[c];
-                    }
-                } else {
-                    return map.mapping[c];
-                }
-            }
-        }
-        return null;
-    }
-
-    public void bindIfNotBound( CharSequence keySeq, Object function ) {
-
-        bind (this, keySeq, function, true);
-    }
-
-    public void bind( CharSequence keySeq, Object function ) {
-
-        bind (this, keySeq, function, false);
-    }
-
-    private static void bind( KeyMap map, CharSequence keySeq, Object function ) {
-
-        bind (map, keySeq, function, false);
-    }
-
-    private static void bind( KeyMap map, CharSequence keySeq, Object function,
-            boolean onlyIfNotBound ) {
-
-        if (keySeq != null && keySeq.length() > 0) {
-            for (int i = 0; i < keySeq.length(); i++) {
-                char c = keySeq.charAt(i);
-                if (c >= map.mapping.length) {
-                    return;
-                }
-                if (i < keySeq.length() - 1) {
-                    if (!(map.mapping[c] instanceof KeyMap)) {
-                        KeyMap m = new KeyMap("anonymous");
-                        if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
-                            m.anotherKey = map.mapping[c];
-                        }
-                        map.mapping[c] = m;
-                    }
-                    map = (KeyMap) map.mapping[c];
-                } else {
-                    if (function == null) {
-                        function = NULL_FUNCTION;
-                    }
-                    if (map.mapping[c] instanceof KeyMap) {
-                        map.anotherKey = function;
-                    } else {
-                        Object op = map.mapping[c];
-                        if (onlyIfNotBound == false
-                            || op == null
-                            || op == Operation.DO_LOWERCASE_VERSION
-                            || op == Operation.VI_MOVEMENT_MODE ) {
-
-                        }
-
-                        map.mapping[c] = function;
-                    }
-                }
-            }
-        }
-    }
-
-    public void setBlinkMatchingParen(boolean on) {
-        if (on) {
-            bind( "}", Operation.INSERT_CLOSE_CURLY );
-            bind( ")", Operation.INSERT_CLOSE_PAREN );
-            bind( "]", Operation.INSERT_CLOSE_SQUARE );
-        }
-    }
-
-    private static void bindArrowKeys(KeyMap map) {
-
-        // MS-DOS
-        bind( map, "\033[0A", Operation.PREVIOUS_HISTORY );
-        bind( map, "\033[0B", Operation.BACKWARD_CHAR );
-        bind( map, "\033[0C", Operation.FORWARD_CHAR );
-        bind( map, "\033[0D", Operation.NEXT_HISTORY );
-
-        // Windows
-        bind( map, "\340\000", Operation.KILL_WHOLE_LINE );
-        bind( map, "\340\107", Operation.BEGINNING_OF_LINE );
-        bind( map, "\340\110", Operation.PREVIOUS_HISTORY );
-        bind( map, "\340\111", Operation.BEGINNING_OF_HISTORY );
-        bind( map, "\340\113", Operation.BACKWARD_CHAR );
-        bind( map, "\340\115", Operation.FORWARD_CHAR );
-        bind( map, "\340\117", Operation.END_OF_LINE );
-        bind( map, "\340\120", Operation.NEXT_HISTORY );
-        bind( map, "\340\121", Operation.END_OF_HISTORY );
-        bind( map, "\340\122", Operation.OVERWRITE_MODE );
-        bind( map, "\340\123", Operation.DELETE_CHAR );
-
-        bind( map, "\000\107", Operation.BEGINNING_OF_LINE );
-        bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
-        bind( map, "\000\111", Operation.BEGINNING_OF_HISTORY );
-        bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
-        bind( map, "\000\113", Operation.BACKWARD_CHAR );
-        bind( map, "\000\115", Operation.FORWARD_CHAR );
-        bind( map, "\000\117", Operation.END_OF_LINE );
-        bind( map, "\000\120", Operation.NEXT_HISTORY );
-        bind( map, "\000\121", Operation.END_OF_HISTORY );
-        bind( map, "\000\122", Operation.OVERWRITE_MODE );
-        bind( map, "\000\123", Operation.DELETE_CHAR );
-
-        bind( map, "\033[A", Operation.PREVIOUS_HISTORY );
-        bind( map, "\033[B", Operation.NEXT_HISTORY );
-        bind( map, "\033[C", Operation.FORWARD_CHAR );
-        bind( map, "\033[D", Operation.BACKWARD_CHAR );
-        bind( map, "\033[H", Operation.BEGINNING_OF_LINE );
-        bind( map, "\033[F", Operation.END_OF_LINE );
-
-        bind( map, "\033OA", Operation.PREVIOUS_HISTORY );
-        bind( map, "\033OB", Operation.NEXT_HISTORY );
-        bind( map, "\033OC", Operation.FORWARD_CHAR );
-        bind( map, "\033OD", Operation.BACKWARD_CHAR );
-        bind( map, "\033OH", Operation.BEGINNING_OF_LINE );
-        bind( map, "\033OF", Operation.END_OF_LINE );
-
-        bind( map, "\033[1~", Operation.BEGINNING_OF_LINE);
-        bind( map, "\033[4~", Operation.END_OF_LINE);
-        bind( map, "\033[3~", Operation.DELETE_CHAR);
-
-        // MINGW32
-        bind( map, "\0340H", Operation.PREVIOUS_HISTORY );
-        bind( map, "\0340P", Operation.NEXT_HISTORY );
-        bind( map, "\0340M", Operation.FORWARD_CHAR );
-        bind( map, "\0340K", Operation.BACKWARD_CHAR );
-    }
-
-//    public boolean isConvertMetaCharsToAscii() {
-//        return convertMetaCharsToAscii;
-//    }
-
-//    public void setConvertMetaCharsToAscii(boolean convertMetaCharsToAscii) {
-//        this.convertMetaCharsToAscii = convertMetaCharsToAscii;
-//    }
-
-    public static boolean isMeta( char c ) {
-        return c > 0x7f && c <= 0xff;
-    }
-
-    public static char unMeta( char c ) {
-        return (char) (c & 0x7F);
-    }
-
-    public static char meta( char c ) {
-        return (char) (c | 0x80);
-    }
-
-    public static Map<String, KeyMap> keyMaps() {
-        Map<String, KeyMap> keyMaps = new HashMap<String, KeyMap>();
-
-        KeyMap emacs = emacs();
-        bindArrowKeys(emacs);
-        keyMaps.put(EMACS, emacs);
-        keyMaps.put(EMACS_STANDARD, emacs);
-        keyMaps.put(EMACS_CTLX, (KeyMap) emacs.getBound("\u0018"));
-        keyMaps.put(EMACS_META, (KeyMap) emacs.getBound("\u001b"));
-
-        KeyMap viMov = viMovement();
-        bindArrowKeys(viMov);
-        keyMaps.put(VI_MOVE, viMov);
-        keyMaps.put("vi-command", viMov);
-        keyMaps.put("vi", viMov);
-
-        KeyMap viIns = viInsertion();
-        bindArrowKeys(viIns);
-        keyMaps.put(VI_INSERT, viIns);
-
-        return keyMaps;
-    }
-
-    public static KeyMap emacs() {
-        Object[] map = new Object[KEYMAP_LENGTH];
-        Object[] ctrl = new Object[] {
-                        // Control keys.
-                        Operation.SET_MARK,                 /* Control-@ */
-                        Operation.BEGINNING_OF_LINE,        /* Control-A */
-                        Operation.BACKWARD_CHAR,            /* Control-B */
-                        Operation.INTERRUPT,                /* Control-C */
-                        Operation.EXIT_OR_DELETE_CHAR,      /* Control-D */
-                        Operation.END_OF_LINE,              /* Control-E */
-                        Operation.FORWARD_CHAR,             /* Control-F */
-                        Operation.ABORT,                    /* Control-G */
-                        Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
-                        Operation.COMPLETE,                 /* Control-I */
-                        Operation.ACCEPT_LINE,              /* Control-J */
-                        Operation.KILL_LINE,                /* Control-K */
-                        Operation.CLEAR_SCREEN,             /* Control-L */
-                        Operation.ACCEPT_LINE,              /* Control-M */
-                        Operation.NEXT_HISTORY,             /* Control-N */
-                        null,                               /* Control-O */
-                        Operation.PREVIOUS_HISTORY,         /* Control-P */
-                        Operation.QUOTED_INSERT,            /* Control-Q */
-                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
-                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
-                        Operation.TRANSPOSE_CHARS,          /* Control-T */
-                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
-                        Operation.QUOTED_INSERT,            /* Control-V */
-                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
-                        emacsCtrlX(),                       /* Control-X */
-                        Operation.YANK,                     /* Control-Y */
-                        null,                               /* Control-Z */
-                        emacsMeta(),                        /* Control-[ */
-                        null,                               /* Control-\ */
-                        Operation.CHARACTER_SEARCH,         /* Control-] */
-                        null,                               /* Control-^ */
-                        Operation.UNDO,                     /* Control-_ */
-                };
-        System.arraycopy( ctrl, 0, map, 0, ctrl.length );
-        for (int i = 32; i < 256; i++) {
-            map[i] = Operation.SELF_INSERT;
-        }
-        map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
-        return new KeyMap(EMACS, map);
-    }
-
-    public static final char CTRL_D = (char) 4;
-    public static final char CTRL_G = (char) 7;
-    public static final char CTRL_H = (char) 8;
-    public static final char CTRL_I = (char) 9;
-    public static final char CTRL_J = (char) 10;
-    public static final char CTRL_M = (char) 13;
-    public static final char CTRL_R = (char) 18;
-    public static final char CTRL_S = (char) 19;
-    public static final char CTRL_U = (char) 21;
-    public static final char CTRL_X = (char) 24;
-    public static final char CTRL_Y = (char) 25;
-    public static final char ESCAPE = (char) 27; /* Ctrl-[ */
-    public static final char CTRL_OB = (char) 27; /* Ctrl-[ */
-    public static final char CTRL_CB = (char) 29; /* Ctrl-] */
-
-    public static final int DELETE = (char) 127;
-
-    public static KeyMap emacsCtrlX() {
-        Object[] map = new Object[KEYMAP_LENGTH];
-        map[CTRL_G] = Operation.ABORT;
-        map[CTRL_R] = Operation.RE_READ_INIT_FILE;
-        map[CTRL_U] = Operation.UNDO;
-        map[CTRL_X] = Operation.EXCHANGE_POINT_AND_MARK;
-        map['('] = Operation.START_KBD_MACRO;
-        map[')'] = Operation.END_KBD_MACRO;
-        for (int i = 'A'; i <= 'Z'; i++) {
-            map[i] = Operation.DO_LOWERCASE_VERSION;
-        }
-        map['e'] = Operation.CALL_LAST_KBD_MACRO;
-        map[DELETE] = Operation.KILL_LINE;
-        return new KeyMap(EMACS_CTLX, map);
-    }
-
-    public static KeyMap emacsMeta() {
-        Object[] map = new Object[KEYMAP_LENGTH];
-        map[CTRL_G] = Operation.ABORT;
-        map[CTRL_H] = Operation.BACKWARD_KILL_WORD;
-        map[CTRL_I] = Operation.TAB_INSERT;
-        map[CTRL_J] = Operation.VI_EDITING_MODE;
-        map[CTRL_M] = Operation.VI_EDITING_MODE;
-        map[CTRL_R] = Operation.REVERT_LINE;
-        map[CTRL_Y] = Operation.YANK_NTH_ARG;
-        map[CTRL_OB] = Operation.COMPLETE;
-        map[CTRL_CB] = Operation.CHARACTER_SEARCH_BACKWARD;
-        map[' '] = Operation.SET_MARK;
-        map['#'] = Operation.INSERT_COMMENT;
-        map['&'] = Operation.TILDE_EXPAND;
-        map['*'] = Operation.INSERT_COMPLETIONS;
-        map['-'] = Operation.DIGIT_ARGUMENT;
-        map['.'] = Operation.YANK_LAST_ARG;
-        map['<'] = Operation.BEGINNING_OF_HISTORY;
-        map['='] = Operation.POSSIBLE_COMPLETIONS;
-        map['>'] = Operation.END_OF_HISTORY;
-        map['?'] = Operation.POSSIBLE_COMPLETIONS;
-        for (int i = 'A'; i <= 'Z'; i++) {
-            map[i] = Operation.DO_LOWERCASE_VERSION;
-        }
-        map['\\'] = Operation.DELETE_HORIZONTAL_SPACE;
-        map['_'] = Operation.YANK_LAST_ARG;
-        map['b'] = Operation.BACKWARD_WORD;
-        map['c'] = Operation.CAPITALIZE_WORD;
-        map['d'] = Operation.KILL_WORD;
-        map['f'] = Operation.FORWARD_WORD;
-        map['l'] = Operation.DOWNCASE_WORD;
-        map['p'] = Operation.NON_INCREMENTAL_REVERSE_SEARCH_HISTORY;
-        map['r'] = Operation.REVERT_LINE;
-        map['t'] = Operation.TRANSPOSE_WORDS;
-        map['u'] = Operation.UPCASE_WORD;
-        map['y'] = Operation.YANK_POP;
-        map['~'] = Operation.TILDE_EXPAND;
-        map[DELETE] = Operation.BACKWARD_KILL_WORD;
-        return new KeyMap(EMACS_META, map);
-    }
-
-    public static KeyMap viInsertion() {
-        Object[] map = new Object[KEYMAP_LENGTH];
-        Object[] ctrl = new Object[] {
-                        // Control keys.
-                        null,                               /* Control-@ */
-                        Operation.SELF_INSERT,              /* Control-A */
-                        Operation.SELF_INSERT,              /* Control-B */
-                        Operation.SELF_INSERT,              /* Control-C */
-                        Operation.VI_EOF_MAYBE,             /* Control-D */
-                        Operation.SELF_INSERT,              /* Control-E */
-                        Operation.SELF_INSERT,              /* Control-F */
-                        Operation.SELF_INSERT,              /* Control-G */
-                        Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
-                        Operation.COMPLETE,                 /* Control-I */
-                        Operation.ACCEPT_LINE,              /* Control-J */
-                        Operation.SELF_INSERT,              /* Control-K */
-                        Operation.SELF_INSERT,              /* Control-L */
-                        Operation.ACCEPT_LINE,              /* Control-M */
-                        Operation.MENU_COMPLETE,            /* Control-N */
-                        Operation.SELF_INSERT,              /* Control-O */
-                        Operation.MENU_COMPLETE_BACKWARD,   /* Control-P */
-                        Operation.SELF_INSERT,              /* Control-Q */
-                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
-                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
-                        Operation.TRANSPOSE_CHARS,          /* Control-T */
-                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
-                        Operation.QUOTED_INSERT,            /* Control-V */
-                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
-                        Operation.SELF_INSERT,              /* Control-X */
-                        Operation.YANK,                     /* Control-Y */
-                        Operation.SELF_INSERT,              /* Control-Z */
-                        Operation.VI_MOVEMENT_MODE,         /* Control-[ */
-                        Operation.SELF_INSERT,              /* Control-\ */
-                        Operation.SELF_INSERT,              /* Control-] */
-                        Operation.SELF_INSERT,              /* Control-^ */
-                        Operation.UNDO,                     /* Control-_ */
-                };
-        System.arraycopy( ctrl, 0, map, 0, ctrl.length );
-        for (int i = 32; i < 256; i++) {
-            map[i] = Operation.SELF_INSERT;
-        }
-        map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
-        return new KeyMap(VI_INSERT, map);
-    }
-
-    public static KeyMap viMovement() {
-        Object[] map = new Object[KEYMAP_LENGTH];
-        Object[] low = new Object[] {
-                        // Control keys.
-                        null,                               /* Control-@ */
-                        null,                               /* Control-A */
-                        null,                               /* Control-B */
-                        Operation.INTERRUPT,                /* Control-C */
-                        /*
-                         * ^D is supposed to move down half a screen. In bash
-                         * appears to be ignored.
-                         */
-                        Operation.VI_EOF_MAYBE,             /* Control-D */
-                        Operation.EMACS_EDITING_MODE,       /* Control-E */
-                        null,                               /* Control-F */
-                        Operation.ABORT,                    /* Control-G */
-                        Operation.BACKWARD_CHAR,            /* Control-H */
-                        null,                               /* Control-I */
-                        Operation.VI_MOVE_ACCEPT_LINE,      /* Control-J */
-                        Operation.KILL_LINE,                /* Control-K */
-                        Operation.CLEAR_SCREEN,             /* Control-L */
-                        Operation.VI_MOVE_ACCEPT_LINE,      /* Control-M */
-                        Operation.VI_NEXT_HISTORY,          /* Control-N */
-                        null,                               /* Control-O */
-                        Operation.VI_PREVIOUS_HISTORY,      /* Control-P */
-                        /*
-                         * My testing with readline is the ^Q is ignored.
-                         * Maybe this should be null?
-                         */
-                        Operation.QUOTED_INSERT,            /* Control-Q */
-
-                        /*
-                         * TODO - Very broken.  While in forward/reverse
-                         * history search the VI keyset should go out the
-                         * window and we need to enter a very simple keymap.
-                         */
-                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
-                        /* TODO */
-                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
-                        Operation.TRANSPOSE_CHARS,          /* Control-T */
-                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
-                        /* TODO */
-                        Operation.QUOTED_INSERT,            /* Control-V */
-                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
-                        null,                               /* Control-X */
-                        /* TODO */
-                        Operation.YANK,                     /* Control-Y */
-                        null,                               /* Control-Z */
-                        emacsMeta(),                        /* Control-[ */
-                        null,                               /* Control-\ */
-                        /* TODO */
-                        Operation.CHARACTER_SEARCH,         /* Control-] */
-                        null,                               /* Control-^ */
-                        /* TODO */
-                        Operation.UNDO,                     /* Control-_ */
-                        Operation.FORWARD_CHAR,             /* SPACE */
-                        null,                               /* ! */
-                        null,                               /* " */
-                        Operation.VI_INSERT_COMMENT,        /* # */
-                        Operation.END_OF_LINE,              /* $ */
-                        Operation.VI_MATCH,                 /* % */
-                        Operation.VI_TILDE_EXPAND,          /* & */
-                        null,                               /* ' */
-                        null,                               /* ( */
-                        null,                               /* ) */
-                        /* TODO */
-                        Operation.VI_COMPLETE,              /* * */
-                        Operation.VI_NEXT_HISTORY,          /* + */
-                        Operation.VI_CHAR_SEARCH,           /* , */
-                        Operation.VI_PREVIOUS_HISTORY,      /* - */
-                        /* TODO */
-                        Operation.VI_REDO,                  /* . */
-                        Operation.VI_SEARCH,                /* / */
-                        Operation.VI_BEGINNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
-                        Operation.VI_ARG_DIGIT,             /* 1 */
-                        Operation.VI_ARG_DIGIT,             /* 2 */
-                        Operation.VI_ARG_DIGIT,             /* 3 */
-                        Operation.VI_ARG_DIGIT,             /* 4 */
-                        Operation.VI_ARG_DIGIT,             /* 5 */
-                        Operation.VI_ARG_DIGIT,             /* 6 */
-                        Operation.VI_ARG_DIGIT,             /* 7 */
-                        Operation.VI_ARG_DIGIT,             /* 8 */
-                        Operation.VI_ARG_DIGIT,             /* 9 */
-                        null,                               /* : */
-                        Operation.VI_CHAR_SEARCH,           /* ; */
-                        null,                               /* < */
-                        Operation.VI_COMPLETE,              /* = */
-                        null,                               /* > */
-                        Operation.VI_SEARCH,                /* ? */
-                        null,                               /* @ */
-                        Operation.VI_APPEND_EOL,            /* A */
-                        Operation.VI_PREV_WORD,             /* B */
-                        Operation.VI_CHANGE_TO_EOL,         /* C */
-                        Operation.VI_DELETE_TO_EOL,         /* D */
-                        Operation.VI_END_WORD,              /* E */
-                        Operation.VI_CHAR_SEARCH,           /* F */
-                        /* I need to read up on what this does */
-                        Operation.VI_FETCH_HISTORY,         /* G */
-                        null,                               /* H */
-                        Operation.VI_INSERT_BEG,            /* I */
-                        null,                               /* J */
-                        null,                               /* K */
-                        null,                               /* L */
-                        null,                               /* M */
-                        Operation.VI_SEARCH_AGAIN,          /* N */
-                        null,                               /* O */
-                        Operation.VI_PUT,                   /* P */
-                        null,                               /* Q */
-                        /* TODO */
-                        Operation.VI_REPLACE,               /* R */
-                        Operation.VI_KILL_WHOLE_LINE,       /* S */
-                        Operation.VI_CHAR_SEARCH,           /* T */
-                        /* TODO */
-                        Operation.REVERT_LINE,              /* U */
-                        null,                               /* V */
-                        Operation.VI_NEXT_WORD,             /* W */
-                        Operation.VI_RUBOUT,                /* X */
-                        Operation.VI_YANK_TO,               /* Y */
-                        null,                               /* Z */
-                        null,                               /* [ */
-                        Operation.VI_COMPLETE,              /* \ */
-                        null,                               /* ] */
-                        Operation.VI_FIRST_PRINT,           /* ^ */
-                        Operation.VI_YANK_ARG,              /* _ */
-                        Operation.VI_GOTO_MARK,             /* ` */
-                        Operation.VI_APPEND_MODE,           /* a */
-                        Operation.VI_PREV_WORD,             /* b */
-                        Operation.VI_CHANGE_TO,             /* c */
-                        Operation.VI_DELETE_TO,             /* d */
-                        Operation.VI_END_WORD,              /* e */
-                        Operation.VI_CHAR_SEARCH,           /* f */
-                        null,                               /* g */
-                        Operation.BACKWARD_CHAR,            /* h */
-                        Operation.VI_INSERTION_MODE,        /* i */
-                        Operation.NEXT_HISTORY,             /* j */
-                        Operation.PREVIOUS_HISTORY,         /* k */
-                        Operation.FORWARD_CHAR,             /* l */
-                        Operation.VI_SET_MARK,              /* m */
-                        Operation.VI_SEARCH_AGAIN,          /* n */
-                        null,                               /* o */
-                        Operation.VI_PUT,                   /* p */
-                        null,                               /* q */
-                        Operation.VI_CHANGE_CHAR,           /* r */
-                        Operation.VI_SUBST,                 /* s */
-                        Operation.VI_CHAR_SEARCH,           /* t */
-                        Operation.UNDO,                     /* u */
-                        null,                               /* v */
-                        Operation.VI_NEXT_WORD,             /* w */
-                        Operation.VI_DELETE,                /* x */
-                        Operation.VI_YANK_TO,               /* y */
-                        null,                               /* z */
-                        null,                               /* { */
-                        Operation.VI_COLUMN,                /* | */
-                        null,                               /* } */
-                        Operation.VI_CHANGE_CASE,           /* ~ */
-                        Operation.VI_DELETE                 /* DEL */
-                };
-        System.arraycopy( low, 0, map, 0, low.length );
-        for (int i = 128; i < 256; i++) {
-            map[i] = null;
-        }
-        return new KeyMap(VI_MOVE, map);
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-/**
- * The kill ring class keeps killed text in a fixed size ring. In this
- * class we also keep record of whether or not the last command was a
- * kill or a yank. Depending on this, the class may behave
- * different. For instance, two consecutive kill-word commands fill
- * the same slot such that the next yank will return the two
- * previously killed words instead that only the last one. Likewise
- * yank pop requires that the previous command was either a yank or a
- * yank-pop.
- */
-public final class KillRing {
-
-    /**
-     * Default size is 60, like in emacs.
-     */
-    private static final int DEFAULT_SIZE = 60;
-
-    private final String[] slots;
-    private int head = 0;
-    private boolean lastKill = false;
-    private boolean lastYank = false;
-
-    /**
-     * Creates a new kill ring of the given size.
-     */
-    public KillRing(int size) {
-        slots = new String[size];
-    }
-
-    /**
-     * Creates a new kill ring of the default size. See {@link #DEFAULT_SIZE}.
-     */
-    public KillRing() {
-        this(DEFAULT_SIZE);
-    }
-
-    /**
-     * Resets the last-yank state.
-     */
-    public void resetLastYank() {
-        lastYank = false;
-    }
-
-    /**
-     * Resets the last-kill state.
-     */
-    public void resetLastKill() {
-        lastKill = false;
-    }
-
-    /**
-     * Returns {@code true} if the last command was a yank.
-     */
-    public boolean lastYank() {
-        return lastYank;
-    }
-
-    /**
-     * Adds the string to the kill-ring. Also sets lastYank to false
-     * and lastKill to true.
-     */
-    public void add(String str) {
-        lastYank = false;
-
-        if (lastKill) {
-            if (slots[head] != null) {
-                slots[head] += str;
-                return;
-            }
-        }
-
-        lastKill = true;
-        next();
-        slots[head] = str;
-    }
-
-    /**
-     * Adds the string to the kill-ring product of killing
-     * backwards. If the previous command was a kill text one then
-     * adds the text at the beginning of the previous kill to avoid
-     * that two consecutive backwards kills followed by a yank leaves
-     * things reversed.
-     */
-    public void addBackwards(String str) {
-        lastYank = false;
-
-        if (lastKill) {
-            if (slots[head] != null) {
-                slots[head] = str + slots[head];
-                return;
-            }
-        }
-
-        lastKill = true;
-        next();
-        slots[head] = str;
-    }
-
-    /**
-     * Yanks a previously killed text. Returns {@code null} if the
-     * ring is empty.
-     */
-    public String yank() {
-        lastKill = false;
-        lastYank = true;
-        return slots[head];
-    }
-
-    /**
-     * Moves the pointer to the current slot back and returns the text
-     * in that position. If the previous command was not yank returns
-     * null.
-     */
-    public String yankPop() {
-        lastKill = false;
-        if (lastYank) {
-            prev();
-            return slots[head];
-        }
-        return null;
-    }
-
-    /**
-     * Moves the pointer to the current slot forward. If the end of
-     * the slots is reached then points back to the beginning.
-     */
-    private void next() {
-        if (head == 0 && slots[0] == null) {
-            return;
-        }
-        head++;
-        if (head == slots.length) {
-            head = 0;
-        }
-    }
-
-    /**
-     * Moves the pointer to the current slot backwards. If the
-     * beginning of the slots is reached then traverses the slot
-     * backwards until one with not null content is found.
-     */
-    private void prev() {
-        head--;
-        if (head == -1) {
-            int x = slots.length - 1;
-            for (; x >= 0; x--) {
-                if (slots[x] != null) {
-                    break;
-                }
-            }
-            head = x;
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-/**
- * List of all operations.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.6
- */
-public enum Operation {
-
-    ABORT,
-    ACCEPT_LINE,
-    ARROW_KEY_PREFIX,
-    BACKWARD_BYTE,
-    BACKWARD_CHAR,
-    BACKWARD_DELETE_CHAR,
-    BACKWARD_KILL_LINE,
-    BACKWARD_KILL_WORD,
-    BACKWARD_WORD,
-    BEGINNING_OF_HISTORY,
-    BEGINNING_OF_LINE,
-    CALL_LAST_KBD_MACRO,
-    CAPITALIZE_WORD,
-    CHARACTER_SEARCH,
-    CHARACTER_SEARCH_BACKWARD,
-    CLEAR_SCREEN,
-    COMPLETE,
-    COPY_BACKWARD_WORD,
-    COPY_FORWARD_WORD,
-    COPY_REGION_AS_KILL,
-    DELETE_CHAR,
-    DELETE_CHAR_OR_LIST,
-    DELETE_HORIZONTAL_SPACE,
-    DIGIT_ARGUMENT,
-    DO_LOWERCASE_VERSION,
-    DOWNCASE_WORD,
-    DUMP_FUNCTIONS,
-    DUMP_MACROS,
-    DUMP_VARIABLES,
-    EMACS_EDITING_MODE,
-    END_KBD_MACRO,
-    END_OF_HISTORY,
-    END_OF_LINE,
-    EXCHANGE_POINT_AND_MARK,
-    EXIT_OR_DELETE_CHAR,
-    FORWARD_BACKWARD_DELETE_CHAR,
-    FORWARD_BYTE,
-    FORWARD_CHAR,
-    FORWARD_SEARCH_HISTORY,
-    FORWARD_WORD,
-    HISTORY_SEARCH_BACKWARD,
-    HISTORY_SEARCH_FORWARD,
-    INSERT_CLOSE_CURLY,
-    INSERT_CLOSE_PAREN,
-    INSERT_CLOSE_SQUARE,
-    INSERT_COMMENT,
-    INSERT_COMPLETIONS,
-    INTERRUPT,
-    KILL_WHOLE_LINE,
-    KILL_LINE,
-    KILL_REGION,
-    KILL_WORD,
-    MENU_COMPLETE,
-    MENU_COMPLETE_BACKWARD,
-    NEXT_HISTORY,
-    NON_INCREMENTAL_FORWARD_SEARCH_HISTORY,
-    NON_INCREMENTAL_REVERSE_SEARCH_HISTORY,
-    NON_INCREMENTAL_FORWARD_SEARCH_HISTORY_AGAIN,
-    NON_INCREMENTAL_REVERSE_SEARCH_HISTORY_AGAIN,
-    OLD_MENU_COMPLETE,
-    OVERWRITE_MODE,
-    PASTE_FROM_CLIPBOARD,
-    POSSIBLE_COMPLETIONS,
-    PREVIOUS_HISTORY,
-    QUOTED_INSERT,
-    QUIT,
-    RE_READ_INIT_FILE,
-    REDRAW_CURRENT_LINE,
-    REVERSE_SEARCH_HISTORY,
-    REVERT_LINE,
-    SELF_INSERT,
-    SET_MARK,
-    SKIP_CSI_SEQUENCE,
-    START_KBD_MACRO,
-    TAB_INSERT,
-    TILDE_EXPAND,
-    TRANSPOSE_CHARS,
-    TRANSPOSE_WORDS,
-    TTY_STATUS,
-    UNDO,
-    UNIVERSAL_ARGUMENT,
-    UNIX_FILENAME_RUBOUT,
-    UNIX_LINE_DISCARD,
-    UNIX_WORD_RUBOUT,
-    UPCASE_WORD,
-    YANK,
-    YANK_LAST_ARG,
-    YANK_NTH_ARG,
-    YANK_POP,
-    VI_APPEND_EOL,
-    VI_APPEND_MODE,
-    VI_ARG_DIGIT,
-    VI_BACK_TO_INDENT,
-    VI_BACKWARD_BIGWORD,
-    VI_BACKWARD_WORD,
-    VI_BWORD,
-    VI_CHANGE_CASE,
-    VI_CHANGE_CHAR,
-    VI_CHANGE_TO,
-    VI_CHANGE_TO_EOL,
-    VI_CHAR_SEARCH,
-    VI_COLUMN,
-    VI_COMPLETE,
-    VI_DELETE,
-    VI_DELETE_TO,
-    VI_DELETE_TO_EOL,
-    VI_EDITING_MODE,
-    VI_END_BIGWORD,
-    VI_END_WORD,
-    VI_EOF_MAYBE,
-    VI_EWORD,
-    VI_FWORD,
-    VI_FETCH_HISTORY,
-    VI_FIRST_PRINT,
-    VI_FORWARD_BIGWORD,
-    VI_FORWARD_WORD,
-    VI_GOTO_MARK,
-    VI_INSERT_BEG,
-    VI_INSERTION_MODE,
-    VI_KILL_WHOLE_LINE,
-    VI_MATCH,
-    VI_MOVEMENT_MODE,
-    VI_NEXT_WORD,
-    VI_OVERSTRIKE,
-    VI_OVERSTRIKE_DELETE,
-    VI_PREV_WORD,
-    VI_PUT,
-    VI_REDO,
-    VI_REPLACE,
-    VI_RUBOUT,
-    VI_SEARCH,
-    VI_SEARCH_AGAIN,
-    VI_SET_MARK,
-    VI_SUBST,
-    VI_TILDE_EXPAND,
-    VI_YANK_ARG,
-    VI_YANK_TO,
-    VI_MOVE_ACCEPT_LINE,
-    VI_NEXT_HISTORY,
-    VI_PREVIOUS_HISTORY,
-    VI_INSERT_COMMENT,
-    VI_BEGINNING_OF_LINE_OR_ARG_DIGIT,
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-/**
- * This exception is thrown by {@link ConsoleReader#readLine} when
- * user interrupt handling is enabled and the user types the
- * interrupt character (ctrl-C). The partially entered line is
- * available via the {@link #getPartialLine()} method.
- */
-public class UserInterruptException
-    extends RuntimeException
-{
-    private static final long serialVersionUID = 6172232572140736750L;
-
-    private final String partialLine;
-
-    public UserInterruptException(String partialLine)
-    {
-        this.partialLine = partialLine;
-    }
-
-    /**
-     * @return the partially entered line when ctrl-C was pressed
-     */
-    public String getPartialLine()
-    {
-        return partialLine;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/WCWidth.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console;
-
-public class WCWidth {
-
-    /* The following two functions define the column width of an ISO 10646
-     * character as follows:
-     *
-     *    - The null character (U+0000) has a column width of 0.
-     *
-     *    - Other C0/C1 control characters and DEL will lead to a return
-     *      value of -1.
-     *
-     *    - Non-spacing and enclosing combining characters (general
-     *      category code Mn or Me in the Unicode database) have a
-     *      column width of 0.
-     *
-     *    - SOFT HYPHEN (U+00AD) has a column width of 1.
-     *
-     *    - Other format characters (general category code Cf in the Unicode
-     *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
-     *
-     *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
-     *      have a column width of 0.
-     *
-     *    - Spacing characters in the East Asian Wide (W) or East Asian
-     *      Full-width (F) category as defined in Unicode Technical
-     *      Report #11 have a column width of 2.
-     *
-     *    - All remaining characters (including all printable
-     *      ISO 8859-1 and WGL4 characters, Unicode control characters,
-     *      etc.) have a column width of 1.
-     *
-     * This implementation assumes that wchar_t characters are encoded
-     * in ISO 10646.
-     */
-    public static int wcwidth(int ucs)
-    {
-
-        /* test for 8-bit control characters */
-        if (ucs == 0)
-            return 0;
-        if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
-            return -1;
-
-        /* binary search in table of non-spacing characters */
-        if (bisearch(ucs, combining, combining.length - 1))
-            return 0;
-
-        /* if we arrive here, ucs is not a combining or C0/C1 control character */
-        return 1 +
-                ((ucs >= 0x1100 &&
-                        (ucs <= 0x115f ||                           /* Hangul Jamo init. consonants */
-                                ucs == 0x2329 || ucs == 0x232a ||
-                                (ucs >= 0x2e80 && ucs <= 0xa4cf &&
-                                        ucs != 0x303f) ||           /* CJK ... Yi */
-                                (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
-                                (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
-                                (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
-                                (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
-                                (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
-                                (ucs >= 0xffe0 && ucs <= 0xffe6) ||
-                                (ucs >= 0x20000 && ucs <= 0x2fffd) ||
-                                (ucs >= 0x30000 && ucs <= 0x3fffd))) ? 1 : 0);
-    }
-
-    /* sorted list of non-overlapping intervals of non-spacing characters */
-    /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
-    static Interval[] combining = {
-            new Interval( 0x0300, 0x036F ), new Interval( 0x0483, 0x0486 ), new Interval( 0x0488, 0x0489 ),
-            new Interval( 0x0591, 0x05BD ), new Interval( 0x05BF, 0x05BF ), new Interval( 0x05C1, 0x05C2 ),
-            new Interval( 0x05C4, 0x05C5 ), new Interval( 0x05C7, 0x05C7 ), new Interval( 0x0600, 0x0603 ),
-            new Interval( 0x0610, 0x0615 ), new Interval( 0x064B, 0x065E ), new Interval( 0x0670, 0x0670 ),
-            new Interval( 0x06D6, 0x06E4 ), new Interval( 0x06E7, 0x06E8 ), new Interval( 0x06EA, 0x06ED ),
-            new Interval( 0x070F, 0x070F ), new Interval( 0x0711, 0x0711 ), new Interval( 0x0730, 0x074A ),
-            new Interval( 0x07A6, 0x07B0 ), new Interval( 0x07EB, 0x07F3 ), new Interval( 0x0901, 0x0902 ),
-            new Interval( 0x093C, 0x093C ), new Interval( 0x0941, 0x0948 ), new Interval( 0x094D, 0x094D ),
-            new Interval( 0x0951, 0x0954 ), new Interval( 0x0962, 0x0963 ), new Interval( 0x0981, 0x0981 ),
-            new Interval( 0x09BC, 0x09BC ), new Interval( 0x09C1, 0x09C4 ), new Interval( 0x09CD, 0x09CD ),
-            new Interval( 0x09E2, 0x09E3 ), new Interval( 0x0A01, 0x0A02 ), new Interval( 0x0A3C, 0x0A3C ),
-            new Interval( 0x0A41, 0x0A42 ), new Interval( 0x0A47, 0x0A48 ), new Interval( 0x0A4B, 0x0A4D ),
-            new Interval( 0x0A70, 0x0A71 ), new Interval( 0x0A81, 0x0A82 ), new Interval( 0x0ABC, 0x0ABC ),
-            new Interval( 0x0AC1, 0x0AC5 ), new Interval( 0x0AC7, 0x0AC8 ), new Interval( 0x0ACD, 0x0ACD ),
-            new Interval( 0x0AE2, 0x0AE3 ), new Interval( 0x0B01, 0x0B01 ), new Interval( 0x0B3C, 0x0B3C ),
-            new Interval( 0x0B3F, 0x0B3F ), new Interval( 0x0B41, 0x0B43 ), new Interval( 0x0B4D, 0x0B4D ),
-            new Interval( 0x0B56, 0x0B56 ), new Interval( 0x0B82, 0x0B82 ), new Interval( 0x0BC0, 0x0BC0 ),
-            new Interval( 0x0BCD, 0x0BCD ), new Interval( 0x0C3E, 0x0C40 ), new Interval( 0x0C46, 0x0C48 ),
-            new Interval( 0x0C4A, 0x0C4D ), new Interval( 0x0C55, 0x0C56 ), new Interval( 0x0CBC, 0x0CBC ),
-            new Interval( 0x0CBF, 0x0CBF ), new Interval( 0x0CC6, 0x0CC6 ), new Interval( 0x0CCC, 0x0CCD ),
-            new Interval( 0x0CE2, 0x0CE3 ), new Interval( 0x0D41, 0x0D43 ), new Interval( 0x0D4D, 0x0D4D ),
-            new Interval( 0x0DCA, 0x0DCA ), new Interval( 0x0DD2, 0x0DD4 ), new Interval( 0x0DD6, 0x0DD6 ),
-            new Interval( 0x0E31, 0x0E31 ), new Interval( 0x0E34, 0x0E3A ), new Interval( 0x0E47, 0x0E4E ),
-            new Interval( 0x0EB1, 0x0EB1 ), new Interval( 0x0EB4, 0x0EB9 ), new Interval( 0x0EBB, 0x0EBC ),
-            new Interval( 0x0EC8, 0x0ECD ), new Interval( 0x0F18, 0x0F19 ), new Interval( 0x0F35, 0x0F35 ),
-            new Interval( 0x0F37, 0x0F37 ), new Interval( 0x0F39, 0x0F39 ), new Interval( 0x0F71, 0x0F7E ),
-            new Interval( 0x0F80, 0x0F84 ), new Interval( 0x0F86, 0x0F87 ), new Interval( 0x0F90, 0x0F97 ),
-            new Interval( 0x0F99, 0x0FBC ), new Interval( 0x0FC6, 0x0FC6 ), new Interval( 0x102D, 0x1030 ),
-            new Interval( 0x1032, 0x1032 ), new Interval( 0x1036, 0x1037 ), new Interval( 0x1039, 0x1039 ),
-            new Interval( 0x1058, 0x1059 ), new Interval( 0x1160, 0x11FF ), new Interval( 0x135F, 0x135F ),
-            new Interval( 0x1712, 0x1714 ), new Interval( 0x1732, 0x1734 ), new Interval( 0x1752, 0x1753 ),
-            new Interval( 0x1772, 0x1773 ), new Interval( 0x17B4, 0x17B5 ), new Interval( 0x17B7, 0x17BD ),
-            new Interval( 0x17C6, 0x17C6 ), new Interval( 0x17C9, 0x17D3 ), new Interval( 0x17DD, 0x17DD ),
-            new Interval( 0x180B, 0x180D ), new Interval( 0x18A9, 0x18A9 ), new Interval( 0x1920, 0x1922 ),
-            new Interval( 0x1927, 0x1928 ), new Interval( 0x1932, 0x1932 ), new Interval( 0x1939, 0x193B ),
-            new Interval( 0x1A17, 0x1A18 ), new Interval( 0x1B00, 0x1B03 ), new Interval( 0x1B34, 0x1B34 ),
-            new Interval( 0x1B36, 0x1B3A ), new Interval( 0x1B3C, 0x1B3C ), new Interval( 0x1B42, 0x1B42 ),
-            new Interval( 0x1B6B, 0x1B73 ), new Interval( 0x1DC0, 0x1DCA ), new Interval( 0x1DFE, 0x1DFF ),
-            new Interval( 0x200B, 0x200F ), new Interval( 0x202A, 0x202E ), new Interval( 0x2060, 0x2063 ),
-            new Interval( 0x206A, 0x206F ), new Interval( 0x20D0, 0x20EF ), new Interval( 0x302A, 0x302F ),
-            new Interval( 0x3099, 0x309A ), new Interval( 0xA806, 0xA806 ), new Interval( 0xA80B, 0xA80B ),
-            new Interval( 0xA825, 0xA826 ), new Interval( 0xFB1E, 0xFB1E ), new Interval( 0xFE00, 0xFE0F ),
-            new Interval( 0xFE20, 0xFE23 ), new Interval( 0xFEFF, 0xFEFF ), new Interval( 0xFFF9, 0xFFFB ),
-            new Interval( 0x10A01, 0x10A03 ), new Interval( 0x10A05, 0x10A06 ), new Interval( 0x10A0C, 0x10A0F ),
-            new Interval( 0x10A38, 0x10A3A ), new Interval( 0x10A3F, 0x10A3F ), new Interval( 0x1D167, 0x1D169 ),
-            new Interval( 0x1D173, 0x1D182 ), new Interval( 0x1D185, 0x1D18B ), new Interval( 0x1D1AA, 0x1D1AD ),
-            new Interval( 0x1D242, 0x1D244 ), new Interval( 0xE0001, 0xE0001 ), new Interval( 0xE0020, 0xE007F ),
-            new Interval( 0xE0100, 0xE01EF )
-    };
-
-    private static class Interval {
-        public final int first;
-        public final int last;
-
-        public Interval(int first, int last) {
-            this.first = first;
-            this.last = last;
-        }
-    }
-
-    /* auxiliary function for binary search in interval table */
-    private static boolean bisearch(int ucs, Interval[] table, int max) {
-        int min = 0;
-        int mid;
-
-        if (ucs < table[0].first || ucs > table[max].last)
-            return false;
-        while (max >= min) {
-            mid = (min + max) / 2;
-            if (ucs > table[mid].last)
-                min = mid + 1;
-            else if (ucs < table[mid].first)
-                max = mid - 1;
-            else
-                return true;
-        }
-
-        return false;
-    }
-
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Completer which contains multiple completers and aggregates them together.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class AggregateCompleter
-    implements Completer
-{
-    private final List<Completer> completers = new ArrayList<Completer>();
-
-    public AggregateCompleter() {
-        // empty
-    }
-
-    /**
-     * Construct an AggregateCompleter with the given collection of completers.
-     * The completers will be used in the iteration order of the collection.
-     *
-     * @param completers the collection of completers
-     */
-    public AggregateCompleter(final Collection<Completer> completers) {
-        checkNotNull(completers);
-        this.completers.addAll(completers);
-    }
-
-    /**
-     * Construct an AggregateCompleter with the given completers.
-     * The completers will be used in the order given.
-     *
-     * @param completers the completers
-     */
-    public AggregateCompleter(final Completer... completers) {
-        this(Arrays.asList(completers));
-    }
-
-    /**
-     * Retrieve the collection of completers currently being aggregated.
-     *
-     * @return the aggregated completers
-     */
-    public Collection<Completer> getCompleters() {
-        return completers;
-    }
-
-    /**
-     * Perform a completion operation across all aggregated completers.
-     *
-     * @see Completer#complete(String, int, java.util.List)
-     * @return the highest completion return value from all completers
-     */
-    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
-        // buffer could be null
-        checkNotNull(candidates);
-
-        List<Completion> completions = new ArrayList<Completion>(completers.size());
-
-        // Run each completer, saving its completion results
-        int max = -1;
-        for (Completer completer : completers) {
-            Completion completion = new Completion(candidates);
-            completion.complete(completer, buffer, cursor);
-
-            // Compute the max cursor position
-            max = Math.max(max, completion.cursor);
-
-            completions.add(completion);
-        }
-
-        // Append candidates from completions which have the same cursor position as max
-        for (Completion completion : completions) {
-            if (completion.cursor == max) {
-                candidates.addAll(completion.candidates);
-            }
-        }
-
-        return max;
-    }
-
-    /**
-     * @return a string representing the aggregated completers
-     */
-    @Override
-    public String toString() {
-        return getClass().getSimpleName() + "{" +
-            "completers=" + completers +
-            '}';
-    }
-
-    private class Completion
-    {
-        public final List<CharSequence> candidates;
-
-        public int cursor;
-
-        public Completion(final List<CharSequence> candidates) {
-            checkNotNull(candidates);
-            this.candidates = new LinkedList<CharSequence>(candidates);
-        }
-
-        public void complete(final Completer completer, final String buffer, final int cursor) {
-            checkNotNull(completer);
-            this.cursor = completer.complete(buffer, cursor, candidates);
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AnsiStringsCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import jdk.internal.jline.internal.Ansi;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Completer for a set of strings.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class AnsiStringsCompleter
-    implements Completer
-{
-    private final SortedMap<String, String> strings = new TreeMap<String, String>();
-
-    public AnsiStringsCompleter() {
-        // empty
-    }
-
-    public AnsiStringsCompleter(final Collection<String> strings) {
-        checkNotNull(strings);
-        for (String str : strings) {
-            this.strings.put(Ansi.stripAnsi(str), str);
-        }
-    }
-
-    public AnsiStringsCompleter(final String... strings) {
-        this(Arrays.asList(strings));
-    }
-
-    public Collection<String> getStrings() {
-        return strings.values();
-    }
-
-    public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
-        // buffer could be null
-        checkNotNull(candidates);
-
-        if (buffer == null) {
-            candidates.addAll(strings.values());
-        }
-        else {
-            buffer = Ansi.stripAnsi(buffer);
-            for (Map.Entry<String, String> match : strings.tailMap(buffer).entrySet()) {
-                if (!match.getKey().startsWith(buffer)) {
-                    break;
-                }
-
-                candidates.add(match.getValue());
-            }
-        }
-
-        return candidates.isEmpty() ? -1 : 0;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,457 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import jdk.internal.jline.internal.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
- * This can be used instead of the individual completers having to know about argument parsing semantics.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class ArgumentCompleter
-    implements Completer
-{
-    private final ArgumentDelimiter delimiter;
-
-    private final List<Completer> completers = new ArrayList<Completer>();
-
-    private boolean strict = true;
-
-    /**
-     * Create a new completer with the specified argument delimiter.
-     *
-     * @param delimiter     The delimiter for parsing arguments
-     * @param completers    The embedded completers
-     */
-    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
-        this.delimiter = checkNotNull(delimiter);
-        checkNotNull(completers);
-        this.completers.addAll(completers);
-    }
-
-    /**
-     * Create a new completer with the specified argument delimiter.
-     *
-     * @param delimiter     The delimiter for parsing arguments
-     * @param completers    The embedded completers
-     */
-    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
-        this(delimiter, Arrays.asList(completers));
-    }
-
-    /**
-     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
-     *
-     * @param completers    The embedded completers
-     */
-    public ArgumentCompleter(final Completer... completers) {
-        this(new WhitespaceArgumentDelimiter(), completers);
-    }
-
-    /**
-     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
-     *
-     * @param completers    The embedded completers
-     */
-    public ArgumentCompleter(final List<Completer> completers) {
-        this(new WhitespaceArgumentDelimiter(), completers);
-    }
-
-    /**
-     * If true, a completion at argument index N will only succeed
-     * if all the completions from 0-(N-1) also succeed.
-     */
-    public void setStrict(final boolean strict) {
-        this.strict = strict;
-    }
-
-    /**
-     * Returns whether a completion at argument index N will success
-     * if all the completions from arguments 0-(N-1) also succeed.
-     *
-     * @return  True if strict.
-     * @since 2.3
-     */
-    public boolean isStrict() {
-        return this.strict;
-    }
-
-    /**
-     * @since 2.3
-     */
-    public ArgumentDelimiter getDelimiter() {
-        return delimiter;
-    }
-
-    /**
-     * @since 2.3
-     */
-    public List<Completer> getCompleters() {
-        return completers;
-    }
-
-    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
-        // buffer can be null
-        checkNotNull(candidates);
-
-        ArgumentDelimiter delim = getDelimiter();
-        ArgumentList list = delim.delimit(buffer, cursor);
-        int argpos = list.getArgumentPosition();
-        int argIndex = list.getCursorArgumentIndex();
-
-        if (argIndex < 0) {
-            return -1;
-        }
-
-        List<Completer> completers = getCompleters();
-        Completer completer;
-
-        // if we are beyond the end of the completers, just use the last one
-        if (argIndex >= completers.size()) {
-            completer = completers.get(completers.size() - 1);
-        }
-        else {
-            completer = completers.get(argIndex);
-        }
-
-        // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
-        for (int i = 0; isStrict() && (i < argIndex); i++) {
-            Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
-            String[] args = list.getArguments();
-            String arg = (args == null || i >= args.length) ? "" : args[i];
-
-            List<CharSequence> subCandidates = new LinkedList<CharSequence>();
-
-            if (sub.complete(arg, arg.length(), subCandidates) == -1) {
-                return -1;
-            }
-
-            if (!subCandidates.contains(arg)) {
-                return -1;
-            }
-        }
-
-        int ret = completer.complete(list.getCursorArgument(), argpos, candidates);
-
-        if (ret == -1) {
-            return -1;
-        }
-
-        int pos = ret + list.getBufferPosition() - argpos;
-
-        // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
-        // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
-        //
-        // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
-        // and hit TAB, we want "foo bar" instead of "foo  bar".
-
-        if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
-            for (int i = 0; i < candidates.size(); i++) {
-                CharSequence val = candidates.get(i);
-
-                while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
-                    val = val.subSequence(0, val.length() - 1);
-                }
-
-                candidates.set(i, val);
-            }
-        }
-
-        Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);
-
-        return pos;
-    }
-
-    /**
-     * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
-     * arguments in order to dispatch the arguments to the nested {@link Completer}.
-     *
-     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
-     */
-    public static interface ArgumentDelimiter
-    {
-        /**
-         * Break the specified buffer into individual tokens that can be completed on their own.
-         *
-         * @param buffer    The buffer to split
-         * @param pos       The current position of the cursor in the buffer
-         * @return          The tokens
-         */
-        ArgumentList delimit(CharSequence buffer, int pos);
-
-        /**
-         * Returns true if the specified character is a whitespace parameter.
-         *
-         * @param buffer    The complete command buffer
-         * @param pos       The index of the character in the buffer
-         * @return          True if the character should be a delimiter
-         */
-        boolean isDelimiter(CharSequence buffer, int pos);
-    }
-
-    /**
-     * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
-     * character should be used as a delimiter.
-     *
-     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
-     */
-    public abstract static class AbstractArgumentDelimiter
-        implements ArgumentDelimiter
-    {
-        private char[] quoteChars = {'\'', '"'};
-
-        private char[] escapeChars = {'\\'};
-
-        public void setQuoteChars(final char[] chars) {
-            this.quoteChars = chars;
-        }
-
-        public char[] getQuoteChars() {
-            return this.quoteChars;
-        }
-
-        public void setEscapeChars(final char[] chars) {
-            this.escapeChars = chars;
-        }
-
-        public char[] getEscapeChars() {
-            return this.escapeChars;
-        }
-
-        public ArgumentList delimit(final CharSequence buffer, final int cursor) {
-            List<String> args = new LinkedList<String>();
-            StringBuilder arg = new StringBuilder();
-            int argpos = -1;
-            int bindex = -1;
-            int quoteStart = -1;
-
-            for (int i = 0; (buffer != null) && (i < buffer.length()); i++) {
-                // once we reach the cursor, set the
-                // position of the selected index
-                if (i == cursor) {
-                    bindex = args.size();
-                    // the position in the current argument is just the
-                    // length of the current argument
-                    argpos = arg.length();
-                }
-
-                if (quoteStart < 0 && isQuoteChar(buffer, i)) {
-                    // Start a quote block
-                    quoteStart = i;
-                } else if (quoteStart >= 0) {
-                    // In a quote block
-                    if (buffer.charAt(quoteStart) == buffer.charAt(i) && !isEscaped(buffer, i)) {
-                        // End the block; arg could be empty, but that's fine
-                        args.add(arg.toString());
-                        arg.setLength(0);
-                        quoteStart = -1;
-                    } else if (!isEscapeChar(buffer, i)) {
-                        // Take the next character
-                        arg.append(buffer.charAt(i));
-                    }
-                } else {
-                    // Not in a quote block
-                    if (isDelimiter(buffer, i)) {
-                        if (arg.length() > 0) {
-                            args.add(arg.toString());
-                            arg.setLength(0); // reset the arg
-                        }
-                    } else if (!isEscapeChar(buffer, i)) {
-                        arg.append(buffer.charAt(i));
-                    }
-                }
-            }
-
-            if (cursor == buffer.length()) {
-                bindex = args.size();
-                // the position in the current argument is just the
-                // length of the current argument
-                argpos = arg.length();
-            }
-            if (arg.length() > 0) {
-                args.add(arg.toString());
-            }
-
-            return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
-        }
-
-        /**
-         * 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
-         * returns true from {@link #isDelimiterChar}.
-         *
-         * @param buffer    The complete command buffer
-         * @param pos       The index of the character in the buffer
-         * @return          True if the character should be a delimiter
-         */
-        public boolean isDelimiter(final CharSequence buffer, final int pos) {
-            return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
-        }
-
-        public boolean isQuoted(final CharSequence buffer, final int pos) {
-            return false;
-        }
-
-        public boolean isQuoteChar(final CharSequence buffer, final int pos) {
-            if (pos < 0) {
-                return false;
-            }
-
-            for (int i = 0; (quoteChars != null) && (i < quoteChars.length); i++) {
-                if (buffer.charAt(pos) == quoteChars[i]) {
-                    return !isEscaped(buffer, pos);
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Check if this character is a valid escape char (i.e. one that has not been escaped)
-         */
-        public boolean isEscapeChar(final CharSequence buffer, final int pos) {
-            if (pos < 0) {
-                return false;
-            }
-
-            for (int i = 0; (escapeChars != null) && (i < escapeChars.length); i++) {
-                if (buffer.charAt(pos) == escapeChars[i]) {
-                    return !isEscaped(buffer, pos); // escape escape
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Check if a character is escaped (i.e. if the previous character is an escape)
-         *
-         * @param buffer
-         *          the buffer to check in
-         * @param pos
-         *          the position of the character to check
-         * @return true if the character at the specified position in the given buffer is an escape character and the character immediately preceding it is not an
-         *         escape character.
-         */
-        public boolean isEscaped(final CharSequence buffer, final int pos) {
-            if (pos <= 0) {
-                return false;
-            }
-
-            return isEscapeChar(buffer, pos - 1);
-        }
-
-        /**
-         * 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
-         * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
-         */
-        public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
-    }
-
-    /**
-     * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
-     * {@link Character#isWhitespace}) as being a delimiter.
-     *
-     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
-     */
-    public static class WhitespaceArgumentDelimiter
-        extends AbstractArgumentDelimiter
-    {
-        /**
-         * The character is a delimiter if it is whitespace, and the
-         * preceding character is not an escape character.
-         */
-        @Override
-        public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
-            return Character.isWhitespace(buffer.charAt(pos));
-        }
-    }
-
-    /**
-     * The result of a delimited buffer.
-     *
-     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
-     */
-    public static class ArgumentList
-    {
-        private String[] arguments;
-
-        private int cursorArgumentIndex;
-
-        private int argumentPosition;
-
-        private int bufferPosition;
-
-        /**
-         * @param arguments             The array of tokens
-         * @param cursorArgumentIndex   The token index of the cursor
-         * @param argumentPosition      The position of the cursor in the current token
-         * @param bufferPosition        The position of the cursor in the whole buffer
-         */
-        public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
-            this.arguments = checkNotNull(arguments);
-            this.cursorArgumentIndex = cursorArgumentIndex;
-            this.argumentPosition = argumentPosition;
-            this.bufferPosition = bufferPosition;
-        }
-
-        public void setCursorArgumentIndex(final int i) {
-            this.cursorArgumentIndex = i;
-        }
-
-        public int getCursorArgumentIndex() {
-            return this.cursorArgumentIndex;
-        }
-
-        public String getCursorArgument() {
-            if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
-                return null;
-            }
-
-            return arguments[cursorArgumentIndex];
-        }
-
-        public void setArgumentPosition(final int pos) {
-            this.argumentPosition = pos;
-        }
-
-        public int getArgumentPosition() {
-            return this.argumentPosition;
-        }
-
-        public void setArguments(final String[] arguments) {
-            this.arguments = arguments;
-        }
-
-        public String[] getArguments() {
-            return this.arguments;
-        }
-
-        public void setBufferPosition(final int pos) {
-            this.bufferPosition = pos;
-        }
-
-        public int getBufferPosition() {
-            return this.bufferPosition;
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.CursorBuffer;
-import jdk.internal.jline.internal.Ansi;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.ResourceBundle;
-import java.util.Set;
-
-/**
- * A {@link CompletionHandler} that deals with multiple distinct completions
- * by outputting the complete list of possibilities to the console. This
- * mimics the behavior of the
- * <a href="http://www.gnu.org/directory/readline.html">readline</a> library.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class CandidateListCompletionHandler
-    implements CompletionHandler
-{
-    private boolean printSpaceAfterFullCompletion = true;
-    private boolean stripAnsi;
-
-    public boolean getPrintSpaceAfterFullCompletion() {
-        return printSpaceAfterFullCompletion;
-    }
-
-    public void setPrintSpaceAfterFullCompletion(boolean printSpaceAfterFullCompletion) {
-        this.printSpaceAfterFullCompletion = printSpaceAfterFullCompletion;
-    }
-
-    public boolean isStripAnsi() {
-        return stripAnsi;
-    }
-
-    public void setStripAnsi(boolean stripAnsi) {
-        this.stripAnsi = stripAnsi;
-    }
-
-    // TODO: handle quotes and escaped quotes && enable automatic escaping of whitespace
-
-    public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
-        IOException
-    {
-        CursorBuffer buf = reader.getCursorBuffer();
-
-        // if there is only one completion, then fill in the buffer
-        if (candidates.size() == 1) {
-            String value = Ansi.stripAnsi(candidates.get(0).toString());
-
-            if (buf.cursor == buf.buffer.length()
-                    && printSpaceAfterFullCompletion
-                    && !value.endsWith(" ")) {
-                value += " ";
-            }
-
-            // fail if the only candidate is the same as the current buffer
-            if (value.equals(buf.toString())) {
-                return false;
-            }
-
-            setBuffer(reader, value, pos);
-
-            return true;
-        }
-        else if (candidates.size() > 1) {
-            String value = getUnambiguousCompletions(candidates);
-            setBuffer(reader, value, pos);
-        }
-
-        printCandidates(reader, candidates);
-
-        // redraw the current console buffer
-        reader.drawLine();
-
-        return true;
-    }
-
-    public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
-        IOException
-    {
-        while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
-            // empty
-        }
-
-        reader.putString(value);
-        reader.setCursorPosition(offset + value.length());
-    }
-
-    /**
-     * Print out the candidates. If the size of the candidates is greater than the
-     * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
-     *
-     * @param candidates the list of candidates to print
-     */
-    public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws
-        IOException
-    {
-        Set<CharSequence> distinct = new HashSet<CharSequence>(candidates);
-
-        if (distinct.size() > reader.getAutoprintThreshold()) {
-            //noinspection StringConcatenation
-            reader.println();
-            reader.print(Messages.DISPLAY_CANDIDATES.format(distinct.size()));
-            reader.flush();
-
-            int c;
-
-            String noOpt = Messages.DISPLAY_CANDIDATES_NO.format();
-            String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format();
-            char[] allowed = {yesOpt.charAt(0), noOpt.charAt(0)};
-
-            while ((c = reader.readCharacter(allowed)) != -1) {
-                String tmp = new String(new char[]{(char) c});
-
-                if (noOpt.startsWith(tmp)) {
-                    reader.println();
-                    return;
-                }
-                else if (yesOpt.startsWith(tmp)) {
-                    break;
-                }
-                else {
-                    reader.beep();
-                }
-            }
-        }
-
-        // copy the values and make them distinct, without otherwise affecting the ordering. Only do it if the sizes differ.
-        if (distinct.size() != candidates.size()) {
-            Collection<CharSequence> copy = new ArrayList<CharSequence>();
-
-            for (CharSequence next : candidates) {
-                if (!copy.contains(next)) {
-                    copy.add(next);
-                }
-            }
-
-            candidates = copy;
-        }
-
-        reader.println();
-        reader.printColumns(candidates);
-    }
-
-    /**
-     * Returns a root that matches all the {@link String} elements of the specified {@link List},
-     * or null if there are no commonalities. For example, if the list contains
-     * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
-     */
-    private String getUnambiguousCompletions(final List<CharSequence> candidates) {
-        if (candidates == null || candidates.isEmpty()) {
-            return null;
-        }
-
-        if (candidates.size() == 1) {
-            return candidates.get(0).toString();
-        }
-
-        // convert to an array for speed
-        String first = null;
-        String[] strings = new String[candidates.size() - 1];
-        for (int i = 0; i < candidates.size(); i++) {
-            String str = candidates.get(i).toString();
-            if (stripAnsi) {
-                str = Ansi.stripAnsi(str);
-            }
-            if (first == null) {
-                first = str;
-            } else {
-                strings[i - 1] = str;
-            }
-        }
-
-        StringBuilder candidate = new StringBuilder();
-
-        for (int i = 0; i < first.length(); i++) {
-            if (startsWith(first.substring(0, i + 1), strings)) {
-                candidate.append(first.charAt(i));
-            }
-            else {
-                break;
-            }
-        }
-
-        return candidate.toString();
-    }
-
-    /**
-     * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
-     */
-    private static boolean startsWith(final String starts, final String[] candidates) {
-        for (String candidate : candidates) {
-            if (!candidate.toLowerCase().startsWith(starts.toLowerCase())) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private static enum Messages
-    {
-        DISPLAY_CANDIDATES,
-        DISPLAY_CANDIDATES_YES,
-        DISPLAY_CANDIDATES_NO,;
-
-        private static final
-        ResourceBundle
-            bundle =
-            ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
-
-        public String format(final Object... args) {
-            if (bundle == null)
-                return "";
-            else
-                return String.format(bundle.getString(name()), args);
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#
-# 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
-#
-
-DISPLAY_CANDIDATES=Display all %d possibilities? (y or n)
-DISPLAY_CANDIDATES_YES=y
-DISPLAY_CANDIDATES_NO=n
-DISPLAY_MORE=--More--
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import java.util.List;
-
-/**
- * A completer is the mechanism by which tab-completion candidates will be resolved.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface Completer
-{
-    //
-    // FIXME: Check if we can use CharSequece for buffer?
-    //
-
-    /**
-     * Populates <i>candidates</i> with a list of possible completions for the <i>buffer</i>.
-     *
-     * The <i>candidates</i> list will not be sorted before being displayed to the user: thus, the
-     * complete method should sort the {@link List} before returning.
-     *
-     * @param buffer        The buffer
-     * @param cursor        The current position of the cursor in the <i>buffer</i>
-     * @param candidates    The {@link List} of candidates to populate
-     * @return              The index of the <i>buffer</i> for which the completion will be relative
-     */
-    int complete(String buffer, int cursor, List<CharSequence> candidates);
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import jdk.internal.jline.console.ConsoleReader;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Handler for dealing with candidates for tab-completion.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface CompletionHandler
-{
-    boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * {@link Completer} for {@link Enum} names.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class EnumCompleter
-    extends StringsCompleter
-{
-    public EnumCompleter(Class<? extends Enum<?>> source) {
-        this(source, true);
-    }
-
-    public EnumCompleter(Class<? extends Enum<?>> source, boolean toLowerCase) {
-        checkNotNull(source);
-
-        for (Enum<?> n : source.getEnumConstants()) {
-            this.getStrings().add(toLowerCase ? n.name().toLowerCase() : n.name());
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import jdk.internal.jline.internal.Configuration;
-
-import java.io.File;
-import java.util.List;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * A file name completer takes the buffer and issues a list of
- * potential completions.
- * <p/>
- * This completer tries to behave as similar as possible to
- * <i>bash</i>'s file name completion (using GNU readline)
- * with the following exceptions:
- * <p/>
- * <ul>
- * <li>Candidates that are directories will end with "/"</li>
- * <li>Wildcard regular expressions are not evaluated or replaced</li>
- * <li>The "~" character can be used to represent the user's home,
- * but it cannot complete to other users' homes, since java does
- * not provide any way of determining that easily</li>
- * </ul>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class FileNameCompleter
-    implements Completer
-{
-    // TODO: Handle files with spaces in them
-
-    private static final boolean OS_IS_WINDOWS;
-
-    static {
-        String os = Configuration.getOsName();
-        OS_IS_WINDOWS = os.contains("windows");
-    }
-
-    public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
-        // buffer can be null
-        checkNotNull(candidates);
-
-        if (buffer == null) {
-            buffer = "";
-        }
-
-        if (OS_IS_WINDOWS) {
-            buffer = buffer.replace('/', '\\');
-        }
-
-        String translated = buffer;
-
-        File homeDir = getUserHome();
-
-        // Special character: ~ maps to the user's home directory
-        if (translated.startsWith("~" + separator())) {
-            translated = homeDir.getPath() + translated.substring(1);
-        }
-        else if (translated.startsWith("~")) {
-            translated = homeDir.getParentFile().getAbsolutePath();
-        }
-        else if (!(new File(translated).isAbsolute())) {
-            String cwd = getUserDir().getAbsolutePath();
-            translated = cwd + separator() + translated;
-        }
-
-        File file = new File(translated);
-        final File dir;
-
-        if (translated.endsWith(separator())) {
-            dir = file;
-        }
-        else {
-            dir = file.getParentFile();
-        }
-
-        File[] entries = dir == null ? new File[0] : dir.listFiles();
-
-        return matchFiles(buffer, translated, entries, candidates);
-    }
-
-    protected String separator() {
-        return File.separator;
-    }
-
-    protected File getUserHome() {
-        return Configuration.getUserHome();
-    }
-
-    protected File getUserDir() {
-        return new File(".");
-    }
-
-    protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
-        if (files == null) {
-            return -1;
-        }
-
-        int matches = 0;
-
-        // first pass: just count the matches
-        for (File file : files) {
-            if (file.getAbsolutePath().startsWith(translated)) {
-                matches++;
-            }
-        }
-        for (File file : files) {
-            if (file.getAbsolutePath().startsWith(translated)) {
-                CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
-                candidates.add(render(file, name).toString());
-            }
-        }
-
-        final int index = buffer.lastIndexOf(separator());
-
-        return index + separator().length();
-    }
-
-    protected CharSequence render(final File file, final CharSequence name) {
-        return name;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import java.util.List;
-
-/**
- * Null completer.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public final class NullCompleter
-    implements Completer
-{
-    public static final NullCompleter INSTANCE = new NullCompleter();
-
-    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
-        return -1;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.completer;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Completer for a set of strings.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class StringsCompleter
-    implements Completer
-{
-    private final SortedSet<String> strings = new TreeSet<String>();
-
-    public StringsCompleter() {
-        // empty
-    }
-
-    public StringsCompleter(final Collection<String> strings) {
-        checkNotNull(strings);
-        getStrings().addAll(strings);
-    }
-
-    public StringsCompleter(final String... strings) {
-        this(Arrays.asList(strings));
-    }
-
-    public Collection<String> getStrings() {
-        return strings;
-    }
-
-    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
-        // buffer could be null
-        checkNotNull(candidates);
-
-        if (buffer == null) {
-            candidates.addAll(strings);
-        }
-        else {
-            for (String match : strings.tailSet(buffer)) {
-                if (!match.startsWith(buffer)) {
-                    break;
-                }
-
-                candidates.add(match);
-            }
-        }
-
-        return candidates.isEmpty() ? -1 : 0;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * 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
- */
-/**
- * Console completer support.
- *
- * @since 2.3
- */
-package jdk.internal.jline.console.completer;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.history;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.Flushable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.io.Reader;
-
-import jdk.internal.jline.internal.Log;
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * {@link History} using a file for persistent backing.
- * <p/>
- * Implementers should install shutdown hook to call {@link FileHistory#flush}
- * to save history to disk.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class FileHistory
-    extends MemoryHistory
-    implements PersistentHistory, Flushable
-{
-    private final File file;
-
-    /**
-     * Load a history file into memory, truncating to default max size.
-     */
-    public FileHistory(final File file) throws IOException {
-        this(file, true);
-    }
-
-    /**
-     * Create a FileHistory, but only initialize if doInit is true. This allows
-     * setting maxSize or other settings; call load() before using if doInit is
-     * false.
-     */
-    public FileHistory(final File file, final boolean doInit) throws IOException {
-        this.file = checkNotNull(file).getAbsoluteFile();
-        if (doInit) {
-            load();
-        }
-    }
-
-    /**
-     * Load history from file, e.g. if using delayed init.
-     */
-    public void load() throws IOException {
-        load(file);
-    }
-
-    public File getFile() {
-        return file;
-    }
-
-    public void load(final File file) throws IOException {
-        checkNotNull(file);
-        if (file.exists()) {
-            Log.trace("Loading history from: ", file);
-            FileReader reader = null;
-            try{
-                reader = new FileReader(file);
-                load(reader);
-            } finally{
-                if(reader != null){
-                    reader.close();
-                }
-            }
-        }
-    }
-
-    public void load(final InputStream input) throws IOException {
-        checkNotNull(input);
-        load(new InputStreamReader(input));
-    }
-
-    public void load(final Reader reader) throws IOException {
-        checkNotNull(reader);
-        BufferedReader input = new BufferedReader(reader);
-
-        String item;
-        while ((item = input.readLine()) != null) {
-            internalAdd(item);
-        }
-    }
-
-    public void flush() throws IOException {
-        Log.trace("Flushing history");
-
-        if (!file.exists()) {
-            File dir = file.getParentFile();
-            if (!dir.exists() && !dir.mkdirs()) {
-                Log.warn("Failed to create directory: ", dir);
-            }
-            if (!file.createNewFile()) {
-                Log.warn("Failed to create file: ", file);
-            }
-        }
-
-        PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
-        try {
-            for (Entry entry : this) {
-                out.println(entry.value());
-            }
-        }
-        finally {
-            out.close();
-        }
-    }
-
-    public void purge() throws IOException {
-        Log.trace("Purging history");
-
-        clear();
-
-        if (!file.delete()) {
-            Log.warn("Failed to delete history file: ", file);
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.history;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-
-/**
- * Console history.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface History
-    extends Iterable<History.Entry>
-{
-    int size();
-
-    boolean isEmpty();
-
-    int index();
-
-    void clear();
-
-    CharSequence get(int index);
-
-    void add(CharSequence line);
-
-    /**
-     * Set the history item at the given index to the given CharSequence.
-     *
-     * @param index the index of the history offset
-     * @param item the new item
-     * @since 2.7
-     */
-    void set(int index, CharSequence item);
-
-    /**
-     * Remove the history element at the given index.
-     *
-     * @param i the index of the element to remove
-     * @return the removed element
-     * @since 2.7
-     */
-    CharSequence remove(int i);
-
-    /**
-     * Remove the first element from history.
-     *
-     * @return the removed element
-     * @since 2.7
-     */
-    CharSequence removeFirst();
-
-    /**
-     * Remove the last element from history
-     *
-     * @return the removed element
-     * @since 2.7
-     */
-    CharSequence removeLast();
-
-    void replace(CharSequence item);
-
-    //
-    // Entries
-    //
-
-    interface Entry
-    {
-        int index();
-
-        CharSequence value();
-    }
-
-    ListIterator<Entry> entries(int index);
-
-    ListIterator<Entry> entries();
-
-    Iterator<Entry> iterator();
-
-    //
-    // Navigation
-    //
-
-    CharSequence current();
-
-    boolean previous();
-
-    boolean next();
-
-    boolean moveToFirst();
-
-    boolean moveToLast();
-
-    boolean moveTo(int index);
-
-    void moveToEnd();
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.history;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Non-persistent {@link History}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class MemoryHistory
-    implements History
-{
-    public static final int DEFAULT_MAX_SIZE = 500;
-
-    private final LinkedList<CharSequence> items = new LinkedList<CharSequence>();
-
-    private int maxSize = DEFAULT_MAX_SIZE;
-
-    private boolean ignoreDuplicates = true;
-
-    private boolean autoTrim = false;
-
-    // NOTE: These are all ideas from looking at the Bash man page:
-
-    // TODO: Add ignore space? (lines starting with a space are ignored)
-
-    // TODO: Add ignore patterns?
-
-    // TODO: Add history timestamp?
-
-    // TODO: Add erase dups?
-
-    private int offset = 0;
-
-    private int index = 0;
-
-    public void setMaxSize(final int maxSize) {
-        this.maxSize = maxSize;
-        maybeResize();
-    }
-
-    public int getMaxSize() {
-        return maxSize;
-    }
-
-    public boolean isIgnoreDuplicates() {
-        return ignoreDuplicates;
-    }
-
-    public void setIgnoreDuplicates(final boolean flag) {
-        this.ignoreDuplicates = flag;
-    }
-
-    public boolean isAutoTrim() {
-        return autoTrim;
-    }
-
-    public void setAutoTrim(final boolean flag) {
-        this.autoTrim = flag;
-    }
-
-    public int size() {
-        return items.size();
-    }
-
-    public boolean isEmpty() {
-        return items.isEmpty();
-    }
-
-    public int index() {
-        return offset + index;
-    }
-
-    public void clear() {
-        items.clear();
-        offset = 0;
-        index = 0;
-    }
-
-    public CharSequence get(final int index) {
-        return items.get(index - offset);
-    }
-
-    public void set(int index, CharSequence item) {
-        items.set(index - offset, item);
-    }
-
-    public void add(CharSequence item) {
-        checkNotNull(item);
-
-        if (isAutoTrim()) {
-            item = String.valueOf(item).trim();
-        }
-
-        if (isIgnoreDuplicates()) {
-            if (!items.isEmpty() && item.equals(items.getLast())) {
-                return;
-            }
-        }
-
-        internalAdd(item);
-    }
-
-    public CharSequence remove(int i) {
-        return items.remove(i);
-    }
-
-    public CharSequence removeFirst() {
-        return items.removeFirst();
-    }
-
-    public CharSequence removeLast() {
-        return items.removeLast();
-    }
-
-    protected void internalAdd(CharSequence item) {
-        items.add(item);
-
-        maybeResize();
-    }
-
-    public void replace(final CharSequence item) {
-        items.removeLast();
-        add(item);
-    }
-
-    private void maybeResize() {
-        while (size() > getMaxSize()) {
-            items.removeFirst();
-            offset++;
-        }
-
-        index = size();
-    }
-
-    public ListIterator<Entry> entries(final int index) {
-        return new EntriesIterator(index - offset);
-    }
-
-    public ListIterator<Entry> entries() {
-        return entries(offset);
-    }
-
-    public Iterator<Entry> iterator() {
-        return entries();
-    }
-
-    private static class EntryImpl
-        implements Entry
-    {
-        private final int index;
-
-        private final CharSequence value;
-
-        public EntryImpl(int index, CharSequence value) {
-            this.index = index;
-            this.value = value;
-        }
-
-        public int index() {
-            return index;
-        }
-
-        public CharSequence value() {
-            return value;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("%d: %s", index, value);
-        }
-    }
-
-    private class EntriesIterator
-        implements ListIterator<Entry>
-    {
-        private final ListIterator<CharSequence> source;
-
-        private EntriesIterator(final int index) {
-            source = items.listIterator(index);
-        }
-
-        public Entry next() {
-            if (!source.hasNext()) {
-                throw new NoSuchElementException();
-            }
-            return new EntryImpl(offset + source.nextIndex(), source.next());
-        }
-
-        public Entry previous() {
-            if (!source.hasPrevious()) {
-                throw new NoSuchElementException();
-            }
-            return new EntryImpl(offset + source.previousIndex(), source.previous());
-        }
-
-        public int nextIndex() {
-            return offset + source.nextIndex();
-        }
-
-        public int previousIndex() {
-            return offset + source.previousIndex();
-        }
-
-        public boolean hasNext() {
-            return source.hasNext();
-        }
-
-        public boolean hasPrevious() {
-            return source.hasPrevious();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-        public void set(final Entry entry) {
-            throw new UnsupportedOperationException();
-        }
-
-        public void add(final Entry entry) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    //
-    // Navigation
-    //
-
-    /**
-     * This moves the history to the last entry. This entry is one position
-     * before the moveToEnd() position.
-     *
-     * @return Returns false if there were no history entries or the history
-     *         index was already at the last entry.
-     */
-    public boolean moveToLast() {
-        int lastEntry = size() - 1;
-        if (lastEntry >= 0 && lastEntry != index) {
-            index = size() - 1;
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Move to the specified index in the history
-     */
-    public boolean moveTo(int index) {
-        index -= offset;
-        if (index >= 0 && index < size() ) {
-            this.index = index;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Moves the history index to the first entry.
-     *
-     * @return Return false if there are no entries in the history or if the
-     *         history is already at the beginning.
-     */
-    public boolean moveToFirst() {
-        if (size() > 0 && index != 0) {
-            index = 0;
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Move to the end of the history buffer. This will be a blank entry, after
-     * all of the other entries.
-     */
-    public void moveToEnd() {
-        index = size();
-    }
-
-    /**
-     * Return the content of the current buffer.
-     */
-    public CharSequence current() {
-        if (index >= size()) {
-            return "";
-        }
-
-        return items.get(index);
-    }
-
-    /**
-     * Move the pointer to the previous element in the buffer.
-     *
-     * @return true if we successfully went to the previous element
-     */
-    public boolean previous() {
-        if (index <= 0) {
-            return false;
-        }
-
-        index--;
-
-        return true;
-    }
-
-    /**
-     * Move the pointer to the next element in the buffer.
-     *
-     * @return true if we successfully went to the next element
-     */
-    public boolean next() {
-        if (index >= size()) {
-            return false;
-        }
-
-        index++;
-
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        for (Entry e : this) {
-            sb.append(e.toString() + "\n");
-        }
-        return sb.toString();
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.history;
-
-import java.io.IOException;
-
-/**
- * Persistent {@link History}.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface PersistentHistory
-    extends History
-{
-    /**
-     * Flush all items to persistent storage.
-     *
-     * @throws IOException  Flush failed
-     */
-    void flush() throws IOException;
-
-    /**
-     * Purge persistent storage and {@link #clear}.
-     *
-     * @throws IOException  Purge failed
-     */
-    void purge() throws IOException;
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * 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
- */
-/**
- * Console history support.
- *
- * @since 2.0
- */
-package jdk.internal.jline.console.history;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.internal;
-
-import jdk.internal.jline.console.ConsoleReader;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.SequenceInputStream;
-import java.util.Enumeration;
-
-// FIXME: Clean up API and move to jline.console.runner package
-
-/**
- * An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
- * It is useful for setting up the {@link System#in} for a generic console.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @since 2.7
- */
-class ConsoleReaderInputStream
-    extends SequenceInputStream
-{
-    private static InputStream systemIn = System.in;
-
-    public static void setIn() throws IOException {
-        setIn(new ConsoleReader());
-    }
-
-    public static void setIn(final ConsoleReader reader) {
-        System.setIn(new ConsoleReaderInputStream(reader));
-    }
-
-    /**
-     * Restore the original {@link System#in} input stream.
-     */
-    public static void restoreIn() {
-        System.setIn(systemIn);
-    }
-
-    public ConsoleReaderInputStream(final ConsoleReader reader) {
-        super(new ConsoleEnumeration(reader));
-    }
-
-    private static class ConsoleEnumeration
-        implements Enumeration<InputStream>
-    {
-        private final ConsoleReader reader;
-        private ConsoleLineInputStream next = null;
-        private ConsoleLineInputStream prev = null;
-
-        public ConsoleEnumeration(final ConsoleReader reader) {
-            this.reader = reader;
-        }
-
-        public InputStream nextElement() {
-            if (next != null) {
-                InputStream n = next;
-                prev = next;
-                next = null;
-
-                return n;
-            }
-
-            return new ConsoleLineInputStream(reader);
-        }
-
-        public boolean hasMoreElements() {
-            // the last line was null
-            if ((prev != null) && (prev.wasNull == true)) {
-                return false;
-            }
-
-            if (next == null) {
-                next = (ConsoleLineInputStream) nextElement();
-            }
-
-            return next != null;
-        }
-    }
-
-    private static class ConsoleLineInputStream
-        extends InputStream
-    {
-        private final ConsoleReader reader;
-        private String line = null;
-        private int index = 0;
-        private boolean eol = false;
-        protected boolean wasNull = false;
-
-        public ConsoleLineInputStream(final ConsoleReader reader) {
-            this.reader = reader;
-        }
-
-        public int read() throws IOException {
-            if (eol) {
-                return -1;
-            }
-
-            if (line == null) {
-                line = reader.readLine();
-            }
-
-            if (line == null) {
-                wasNull = true;
-                return -1;
-            }
-
-            if (index >= line.length()) {
-                eol = true;
-                return '\n'; // lines are ended with a newline
-            }
-
-            return line.charAt(index++);
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.console.internal;
-
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.completer.ArgumentCompleter;
-import jdk.internal.jline.console.completer.Completer;
-import jdk.internal.jline.console.history.FileHistory;
-import jdk.internal.jline.console.history.PersistentHistory;
-import jdk.internal.jline.internal.Configuration;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.StringTokenizer;
-
-// FIXME: Clean up API and move to jline.console.runner package
-
-/**
- * A pass-through application that sets the system input stream to a
- * {@link ConsoleReader} and invokes the specified main method.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @since 2.7
- */
-public class ConsoleRunner
-{
-    public static final String property = "jline.history";
-
-    // FIXME: This is really ugly... re-write this
-
-    public static void main(final String[] args) throws Exception {
-        List<String> argList = new ArrayList<String>(Arrays.asList(args));
-        if (argList.size() == 0) {
-            usage();
-            return;
-        }
-
-        String historyFileName = System.getProperty(ConsoleRunner.property, null);
-
-        String mainClass = argList.remove(0);
-        ConsoleReader reader = new ConsoleReader();
-
-        if (historyFileName != null) {
-            reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
-                String.format(".jline-%s.%s.history", mainClass, historyFileName))));
-        }
-        else {
-            reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
-                String.format(".jline-%s.history", mainClass))));
-        }
-
-        String completors = System.getProperty(ConsoleRunner.class.getName() + ".completers", "");
-        List<Completer> completorList = new ArrayList<Completer>();
-
-        for (StringTokenizer tok = new StringTokenizer(completors, ","); tok.hasMoreTokens();) {
-            @SuppressWarnings("deprecation")
-            Object obj = Class.forName(tok.nextToken()).newInstance();
-            completorList.add((Completer) obj);
-        }
-
-        if (completorList.size() > 0) {
-            reader.addCompleter(new ArgumentCompleter(completorList));
-        }
-
-        ConsoleReaderInputStream.setIn(reader);
-
-        try {
-            Class<?> type = Class.forName(mainClass);
-            Method method = type.getMethod("main", String[].class);
-            String[] mainArgs = argList.toArray(new String[argList.size()]);
-            method.invoke(null, (Object) mainArgs);
-        }
-        finally {
-            // just in case this main method is called from another program
-            ConsoleReaderInputStream.restoreIn();
-            if (reader.getHistory() instanceof PersistentHistory) {
-                ((PersistentHistory) reader.getHistory()).flush();
-            }
-        }
-    }
-
-    private static void usage() {
-        System.out.println("Usage: \n   java " + "[-Djline.history='name'] "
-            + ConsoleRunner.class.getName()
-            + " <target class name> [args]"
-            + "\n\nThe -Djline.history option will avoid history"
-            + "\nmangling when running ConsoleRunner on the same application."
-            + "\n\nargs will be passed directly to the target class name.");
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * 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
- */
-/**
- * Console support.
- *
- * @since 2.0
- */
-package jdk.internal.jline.console;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/AnsiInterpretingOutputStream.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jline.extra;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import jdk.internal.jline.internal.Ansi;
-
-/**A stream that interprets some escape code sequences, and ignores those it does not support.
- */
-public class AnsiInterpretingOutputStream extends OutputStream {
-    private final String encoding;
-    private final OutputStream out;
-    private final Performer performer;
-    private final Map<Character, AnsiCodeHandler> ESCAPE_CODE_ACTIONS = new HashMap<>();
-
-    private boolean inEscapeSequence;
-    private ByteArrayOutputStream escape = new ByteArrayOutputStream();
-
-    public AnsiInterpretingOutputStream(String encoding, OutputStream output, Performer performer) {
-        this.encoding = encoding;
-        this.out = output;
-        this.performer = performer;
-        ESCAPE_CODE_ACTIONS.put('A', code -> {
-            moveCursor(code, 0, -1);
-        });
-        ESCAPE_CODE_ACTIONS.put('B', code -> {
-            moveCursor(code, 0, +1);
-        });
-        ESCAPE_CODE_ACTIONS.put('C', code -> {
-            moveCursor(code, +1, 0);
-        });
-        ESCAPE_CODE_ACTIONS.put('D', code -> {
-            moveCursor(code, -1, 0);
-        });
-        ESCAPE_CODE_ACTIONS.put('K', code -> {
-            BufferState buffer = performer.getBufferState();
-            switch (parseOutIntValue(code, 0)) {
-                case 0:
-                    for (int i = buffer.cursorX; i < buffer.sizeX - 1; i++) {
-                        out.write(' ');
-                    }
-                    performer.setCursorPosition(buffer.cursorX, buffer.cursorY);
-                    break;
-                case 1:
-                    performer.setCursorPosition(0, buffer.cursorY);
-                    for (int i = 0; i < buffer.cursorX; i++) {
-                        out.write(' ');
-                    }
-                    break;
-                case 2:
-                    for (int i = 0; i < buffer.sizeX - 1; i++) {
-                        out.write(' ');
-                    }
-                    performer.setCursorPosition(buffer.cursorX, buffer.cursorY);
-                    break;
-            }
-            out.flush();
-        });
-    }
-
-    @Override
-    public void write(int d) throws IOException {
-        if (inEscapeSequence) {
-            escape.write(d);
-            String escapeCandidate = new String(escape.toByteArray(), encoding);
-            if (Ansi.ANSI_CODE_PATTERN.asPredicate().test(escapeCandidate)) {
-                //escape sequence:
-                char key = escapeCandidate.charAt(escapeCandidate.length() - 1);
-                AnsiCodeHandler handler =
-                        ESCAPE_CODE_ACTIONS.get(key);
-                if (handler != null) {
-                    handler.handle(escapeCandidate);
-                } else {
-                    //unknown escape sequence, ignore
-                }
-                inEscapeSequence = false;
-                escape = null;
-            }
-        } else if (d == '\033') {
-            inEscapeSequence = true;
-            escape = new ByteArrayOutputStream();
-            escape.write(d);
-        } else {
-            out.write(d);
-        }
-    }
-    @Override
-    public void flush() throws IOException {
-        out.flush();
-    }
-
-    private void moveCursor(String code, int dx, int dy) throws IOException {
-        int delta = parseOutIntValue(code, 1);
-        BufferState buffer = performer.getBufferState();
-        int tx = buffer.cursorX + dx * delta;
-        int ty = buffer.cursorY + dy * delta;
-
-        tx = Math.max(0, Math.min(buffer.sizeX - 1, tx));
-        ty = Math.max(0, Math.min(buffer.sizeY - 1, ty));
-
-        performer.setCursorPosition(tx, ty);
-    }
-
-    private int parseOutIntValue(String code, int def) {
-        try {
-            return Integer.parseInt(code.substring(code.indexOf('[') + 1, code.length() - 1));
-        } catch (NumberFormatException ex) {
-            return def;
-        }
-    }
-
-    interface AnsiCodeHandler {
-        public void handle(String code) throws IOException;
-    }
-
-    public interface Performer {
-        public BufferState getBufferState() throws IOException;
-        public void setCursorPosition(int cursorX, int cursorY) throws IOException;
-    }
-
-    public static class BufferState {
-        public final int cursorX;
-        public final int cursorY;
-        public final int sizeX;
-        public final int sizeY;
-
-        public BufferState(int cursorX, int cursorY, int sizeX, int sizeY) {
-            this.cursorX = cursorX;
-            this.cursorY = cursorY;
-            this.sizeX = sizeX;
-            this.sizeY = sizeY;
-        }
-
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,422 +0,0 @@
-/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jline.extra;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.function.Supplier;
-
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.KeyMap;
-import jdk.internal.jline.console.history.History;
-import jdk.internal.jline.console.history.History.Entry;
-import jdk.internal.jline.console.history.MemoryHistory;
-
-/*Public for tests (HistoryTest).
- */
-public abstract class EditingHistory implements History {
-
-    private final History fullHistory;
-    private History currentDelegate;
-
-    protected EditingHistory(ConsoleReader in, Iterable<? extends String> originalHistory) {
-        MemoryHistory fullHistory = new MemoryHistory();
-        fullHistory.setIgnoreDuplicates(false);
-        this.fullHistory = fullHistory;
-        this.currentDelegate = fullHistory;
-        bind(in, CTRL_UP,
-             (Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::previousSnippet));
-        bind(in, CTRL_DOWN,
-             (Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::nextSnippet));
-        if (originalHistory != null) {
-            load(originalHistory);
-        }
-    }
-
-    private void moveHistoryToSnippet(ConsoleReader in, Supplier<Boolean> action) {
-        if (!action.get()) {
-            try {
-                in.beep();
-            } catch (IOException ex) {
-                throw new IllegalStateException(ex);
-            }
-        } else {
-            try {
-                //could use:
-                //in.resetPromptLine(in.getPrompt(), in.getHistory().current().toString(), -1);
-                //but that would mean more re-writing on the screen, (and prints an additional
-                //empty line), so using setBuffer directly:
-                Method setBuffer = ConsoleReader.class.getDeclaredMethod("setBuffer", String.class);
-
-                setBuffer.setAccessible(true);
-                setBuffer.invoke(in, in.getHistory().current().toString());
-                in.flush();
-            } catch (ReflectiveOperationException | IOException ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-    }
-
-    private void bind(ConsoleReader in, String shortcut, Object action) {
-        KeyMap km = in.getKeys();
-        for (int i = 0; i < shortcut.length(); i++) {
-            Object value = km.getBound(Character.toString(shortcut.charAt(i)));
-            if (value instanceof KeyMap) {
-                km = (KeyMap) value;
-            } else {
-                km.bind(shortcut.substring(i), action);
-            }
-        }
-    }
-
-    private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP
-    private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN
-
-    @Override
-    public int size() {
-        return currentDelegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return currentDelegate.isEmpty();
-    }
-
-    @Override
-    public int index() {
-        return currentDelegate.index();
-    }
-
-    @Override
-    public void clear() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.clear();
-    }
-
-    @Override
-    public CharSequence get(int index) {
-        return currentDelegate.get(index);
-    }
-
-    @Override
-    public void add(CharSequence line) {
-        NarrowingHistoryLine currentLine = null;
-        int origIndex = fullHistory.index();
-        int fullSize;
-        try {
-            fullHistory.moveToEnd();
-            fullSize = fullHistory.index();
-            if (currentDelegate == fullHistory) {
-                if (origIndex < fullHistory.index()) {
-                    for (Entry entry : fullHistory) {
-                        if (!(entry.value() instanceof NarrowingHistoryLine))
-                            continue;
-                        int[] cluster = ((NarrowingHistoryLine) entry.value()).span;
-                        if (cluster[0] == origIndex && cluster[1] > cluster[0]) {
-                            currentDelegate = new MemoryHistory();
-                            for (int i = cluster[0]; i <= cluster[1]; i++) {
-                                currentDelegate.add(fullHistory.get(i));
-                            }
-                        }
-                    }
-                }
-            }
-            fullHistory.moveToEnd();
-            while (fullHistory.previous()) {
-                CharSequence c = fullHistory.current();
-                if (c instanceof NarrowingHistoryLine) {
-                    currentLine = (NarrowingHistoryLine) c;
-                    break;
-                }
-            }
-        } finally {
-            fullHistory.moveTo(origIndex);
-        }
-        if (currentLine == null || currentLine.span[1] != (-1)) {
-            line = currentLine = new NarrowingHistoryLine(line, fullSize);
-        }
-        StringBuilder complete = new StringBuilder();
-        for (int i = currentLine.span[0]; i < fullSize; i++) {
-            complete.append(fullHistory.get(i));
-        }
-        complete.append(line);
-        if (isComplete(complete)) {
-            currentLine.span[1] = fullSize; //TODO: +1?
-            currentDelegate = fullHistory;
-        }
-        fullHistory.add(line);
-    }
-
-    protected abstract boolean isComplete(CharSequence input);
-
-    @Override
-    public void set(int index, CharSequence item) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.set(index, item);
-    }
-
-    @Override
-    public CharSequence remove(int i) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.remove(i);
-    }
-
-    @Override
-    public CharSequence removeFirst() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.removeFirst();
-    }
-
-    @Override
-    public CharSequence removeLast() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.removeLast();
-    }
-
-    @Override
-    public void replace(CharSequence item) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.replace(item);
-    }
-
-    @Override
-    public ListIterator<Entry> entries(int index) {
-        return currentDelegate.entries(index);
-    }
-
-    @Override
-    public ListIterator<Entry> entries() {
-        return currentDelegate.entries();
-    }
-
-    @Override
-    public Iterator<Entry> iterator() {
-        return currentDelegate.iterator();
-    }
-
-    @Override
-    public CharSequence current() {
-        return currentDelegate.current();
-    }
-
-    @Override
-    public boolean previous() {
-        return currentDelegate.previous();
-    }
-
-    @Override
-    public boolean next() {
-        return currentDelegate.next();
-    }
-
-    @Override
-    public boolean moveToFirst() {
-        return currentDelegate.moveToFirst();
-    }
-
-    @Override
-    public boolean moveToLast() {
-        return currentDelegate.moveToLast();
-    }
-
-    @Override
-    public boolean moveTo(int index) {
-        return currentDelegate.moveTo(index);
-    }
-
-    @Override
-    public void moveToEnd() {
-        currentDelegate.moveToEnd();
-    }
-
-    public boolean previousSnippet() {
-        while (previous()) {
-            if (current() instanceof NarrowingHistoryLine) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public boolean nextSnippet() {
-        boolean success = false;
-
-        while (next()) {
-            success = true;
-
-            if (current() instanceof NarrowingHistoryLine) {
-                return true;
-            }
-        }
-
-        return success;
-    }
-
-    public final void load(Iterable<? extends String> originalHistory) {
-        NarrowingHistoryLine currentHistoryLine = null;
-        boolean start = true;
-        int currentLine = 0;
-        for (String historyItem : originalHistory) {
-            StringBuilder line = new StringBuilder(historyItem);
-            int trailingBackSlashes = countTrailintBackslashes(line);
-            boolean continuation = trailingBackSlashes % 2 != 0;
-            line.delete(line.length() - trailingBackSlashes / 2 - (continuation ? 1 : 0), line.length());
-            if (start) {
-                class PersistentNarrowingHistoryLine extends NarrowingHistoryLine implements PersistentEntryMarker {
-                    public PersistentNarrowingHistoryLine(CharSequence delegate, int start) {
-                        super(delegate, start);
-                    }
-                }
-                fullHistory.add(currentHistoryLine = new PersistentNarrowingHistoryLine(line, currentLine));
-            } else {
-                class PersistentLine implements CharSequence, PersistentEntryMarker {
-                    private final CharSequence delegate;
-                    public PersistentLine(CharSequence delegate) {
-                        this.delegate = delegate;
-                    }
-                    @Override public int length() {
-                        return delegate.length();
-                    }
-                    @Override public char charAt(int index) {
-                        return delegate.charAt(index);
-                    }
-                    @Override public CharSequence subSequence(int start, int end) {
-                        return delegate.subSequence(start, end);
-                    }
-                    @Override public String toString() {
-                        return delegate.toString();
-                    }
-                }
-                fullHistory.add(new PersistentLine(line));
-            }
-            start = !continuation;
-            currentHistoryLine.span[1] = currentLine;
-            currentLine++;
-        }
-    }
-
-    public Collection<? extends String> save() {
-        Collection<String> result = new ArrayList<>();
-        Iterator<Entry> entries = fullHistory.iterator();
-
-        if (entries.hasNext()) {
-            Entry entry = entries.next();
-            while (entry != null) {
-                StringBuilder historyLine = new StringBuilder(entry.value());
-                int trailingBackSlashes = countTrailintBackslashes(historyLine);
-                for (int i = 0; i < trailingBackSlashes; i++) {
-                    historyLine.append("\\");
-                }
-                entry = entries.hasNext() ? entries.next() : null;
-                if (entry != null && !(entry.value() instanceof NarrowingHistoryLine)) {
-                    historyLine.append("\\");
-                }
-                result.add(historyLine.toString());
-            }
-        }
-
-        return result;
-    }
-
-    private int countTrailintBackslashes(CharSequence text) {
-        int count = 0;
-
-        for (int i = text.length() - 1; i >= 0; i--) {
-            if (text.charAt(i) == '\\') {
-                count++;
-            } else {
-                break;
-            }
-        }
-
-        return count;
-    }
-
-    public List<String> entries(boolean currentSession) {
-        List<String> result = new ArrayList<>();
-
-        for (Entry e : fullHistory) {
-            if (!currentSession || !(e.value() instanceof PersistentEntryMarker)) {
-                result.add(e.value().toString());
-            }
-        }
-
-        return result;
-    }
-
-    public void fullHistoryReplace(String source) {
-        fullHistory.removeLast();
-        for (String line : source.split("\\R")) {
-            fullHistory.add(line);
-        }
-    }
-
-    private class NarrowingHistoryLine implements CharSequence {
-        private final CharSequence delegate;
-        private final int[] span;
-
-        public NarrowingHistoryLine(CharSequence delegate, int start) {
-            this.delegate = delegate;
-            this.span = new int[] {start, -1};
-        }
-
-        @Override
-        public int length() {
-            return delegate.length();
-        }
-
-        @Override
-        public char charAt(int index) {
-            return delegate.charAt(index);
-        }
-
-        @Override
-        public CharSequence subSequence(int start, int end) {
-            return delegate.subSequence(start, end);
-        }
-
-        @Override
-        public String toString() {
-            return delegate.toString();
-        }
-
-    }
-
-    private interface PersistentEntryMarker {}
-}
-
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Ansi.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.util.regex.Pattern;
-
-/**
- * Ansi support.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.13
- */
-public class Ansi {
-
-    public static String stripAnsi(String str) {
-        if (str == null) return "";
-        return ANSI_CODE_PATTERN.matcher(str).replaceAll("");
-        //was:
-//        try {
-//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-//            AnsiOutputStream aos = new AnsiOutputStream(baos);
-//            aos.write(str.getBytes());
-//            aos.close();
-//            return baos.toString();
-//        } catch (IOException e) {
-//            return str;
-//        }
-    }
-
-    public static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[\060-\077]*[\040-\057]*[\100-\176]");
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.FileNotFoundException;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.util.Map;
-import java.util.Properties;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Provides access to configuration values.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.4
- */
-public class Configuration
-{
-    /**
-     * System property which can point to a file or URL containing configuration properties to load.
-     *
-     * @since 2.7
-     */
-    public static final String JLINE_CONFIGURATION = "jline.configuration";
-
-    /**
-     * Default configuration file name loaded from user's home directory.
-     */
-    public static final String JLINE_RC = ".jline.rc";
-
-    private static volatile Properties properties;
-
-    private static Properties initProperties() {
-        URL url = determineUrl();
-        Properties props = new Properties();
-        try {
-            loadProperties(url, props);
-        }
-        catch (FileNotFoundException e) {
-            // debug here and no stack trace, as this can happen normally if default jline.rc file is missing
-            Log.debug("Unable to read configuration: ", e.toString());
-        }
-        catch (IOException e) {
-            Log.warn("Unable to read configuration from: ", url, e);
-        }
-        return props;
-    }
-
-    private static void loadProperties(final URL url, final Properties props) throws IOException {
-        Log.debug("Loading properties from: ", url);
-        InputStream input = url.openStream();
-        try {
-            props.load(new BufferedInputStream(input));
-        }
-        finally {
-            try {
-                input.close();
-            }
-            catch (IOException e) {
-                // ignore
-            }
-        }
-
-        if (Log.DEBUG) {
-            Log.debug("Loaded properties:");
-            for (Map.Entry<Object,Object> entry : props.entrySet()) {
-                Log.debug("  ", entry.getKey(), "=", entry.getValue());
-            }
-        }
-    }
-
-    private static URL determineUrl() {
-        // See if user has customized the configuration location via sysprop
-        String tmp = System.getProperty(JLINE_CONFIGURATION);
-        if (tmp != null) {
-            return Urls.create(tmp);
-        }
-        else {
-            // Otherwise try the default
-            File file = new File(getUserHome(), JLINE_RC);
-            return Urls.create(file);
-        }
-    }
-
-    /**
-     * @since 2.7
-     */
-    public static void reset() {
-        Log.debug("Resetting");
-        properties = null;
-
-        // force new properties to load
-        getProperties();
-    }
-
-    /**
-     * @since 2.7
-     */
-    public static Properties getProperties() {
-        // Not sure its worth to guard this with any synchronization, volatile field probably sufficient
-        if (properties == null) {
-            properties = initProperties();
-        }
-        return properties;
-    }
-
-    public static String getString(final String name, final String defaultValue) {
-        checkNotNull(name);
-
-        String value;
-
-        // Check sysprops first, it always wins
-        value = System.getProperty(name);
-
-        if (value == null) {
-            // Next try userprops
-            value = getProperties().getProperty(name);
-
-            if (value == null) {
-                // else use the default
-                value = defaultValue;
-            }
-        }
-
-        return value;
-    }
-
-    public static String getString(final String name) {
-        return getString(name, null);
-    }
-
-    public static boolean getBoolean(final String name) {
-        return getBoolean(name, false);
-    }
-
-    public static boolean getBoolean(final String name, final boolean defaultValue) {
-        String value = getString(name);
-        if (value == null) {
-            return defaultValue;
-        }
-        return value.length() == 0
-            || value.equalsIgnoreCase("1")
-            || value.equalsIgnoreCase("on")
-            || value.equalsIgnoreCase("true");
-    }
-
-    /**
-     * @since 2.6
-     */
-    public static int getInteger(final String name, final int defaultValue) {
-        String str = getString(name);
-        if (str == null) {
-            return defaultValue;
-        }
-        return Integer.parseInt(str);
-    }
-
-    /**
-     * @since 2.6
-     */
-    public static long getLong(final String name, final long defaultValue) {
-        String str = getString(name);
-        if (str == null) {
-            return defaultValue;
-        }
-        return Long.parseLong(str);
-    }
-
-    //
-    // System property helpers
-    //
-
-    /**
-     * @since 2.7
-     */
-    public static String getLineSeparator() {
-        return System.getProperty("line.separator");
-    }
-
-    public static File getUserHome() {
-        return new File(System.getProperty("user.home"));
-    }
-
-    public static String getOsName() {
-        return System.getProperty("os.name").toLowerCase();
-    }
-
-    /**
-     * @since 2.7
-     */
-    public static boolean isWindows() {
-        return getOsName().startsWith("windows");
-    }
-
-    public static boolean isHpux() {
-        return getOsName().startsWith("hp");
-    }
-
-    // FIXME: Sort out use of property access of file.encoding in InputStreamReader, should consolidate configuration access here
-
-    public static String getFileEncoding() {
-        return System.getProperty("file.encoding");
-    }
-
-    /**
-     * Get the default encoding.  Will first look at the LC_ALL, LC_CTYPE, and LANG environment variables, then the input.encoding
-     * system property, then the default charset according to the JVM.
-     *
-     * @return The default encoding to use when none is specified.
-     */
-    public static String getEncoding() {
-        // Check for standard locale environment variables, in order of precedence, first.
-        // See http://www.gnu.org/s/libc/manual/html_node/Locale-Categories.html
-        for (String envOption : new String[]{"LC_ALL", "LC_CTYPE", "LANG"}) {
-            String envEncoding = extractEncodingFromCtype(System.getenv(envOption));
-            if (envEncoding != null) {
-                try {
-                    if (Charset.isSupported(envEncoding)) {
-                        return envEncoding;
-                    }
-                } catch (IllegalCharsetNameException e) {
-                    continue;
-                }
-            }
-        }
-        return getString("input.encoding", Charset.defaultCharset().name());
-    }
-
-    /**
-     * Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
-     * environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
-     *
-     * @param ctype The ctype to parse, may be null
-     * @return The encoding, if one was present, otherwise null
-     */
-    static String extractEncodingFromCtype(String ctype) {
-        if (ctype != null && ctype.indexOf('.') > 0) {
-            String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
-            if (encodingAndModifier.indexOf('@') > 0) {
-                return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
-            } else {
-                return encodingAndModifier;
-            }
-        }
-        return null;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Curses.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Stack;
-
-/**
- * Curses helper methods.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- */
-public class Curses {
-
-    private static Object[] sv = new Object[26];
-    private static Object[] dv = new Object[26];
-
-    private static final int IFTE_NONE = 0;
-    private static final int IFTE_IF = 1;
-    private static final int IFTE_THEN = 2;
-    private static final int IFTE_ELSE = 3;
-
-    /**
-     * Print the given terminal capabilities
-     *
-     * @param out the output stream
-     * @param str the capability to output
-     * @param params optional parameters
-     * @throws IOException if an error occurs
-     */
-    public static void tputs(Writer out, String str, Object... params) throws IOException {
-        int index = 0;
-        int length = str.length();
-        int ifte = IFTE_NONE;
-        boolean exec = true;
-        Stack<Object> stack = new Stack<Object>();
-        while (index < length) {
-            char ch = str.charAt(index++);
-            switch (ch) {
-                case '\\':
-                    ch = str.charAt(index++);
-                    if (ch >= '0' && ch <= '9') {
-                        throw new UnsupportedOperationException(); // todo
-                    } else {
-                        switch (ch) {
-                            case 'e':
-                            case 'E':
-                                if (exec) {
-                                    out.write(27); // escape
-                                }
-                                break;
-                            case 'n':
-                                out.write('\n');
-                                break;
-//                        case 'l':
-//                            rawPrint('\l');
-//                            break;
-                            case 'r':
-                                if (exec) {
-                                    out.write('\r');
-                                }
-                                break;
-                            case 't':
-                                if (exec) {
-                                    out.write('\t');
-                                }
-                                break;
-                            case 'b':
-                                if (exec) {
-                                    out.write('\b');
-                                }
-                                break;
-                            case 'f':
-                                if (exec) {
-                                    out.write('\f');
-                                }
-                                break;
-                            case 's':
-                                if (exec) {
-                                    out.write(' ');
-                                }
-                                break;
-                            case ':':
-                            case '^':
-                            case '\\':
-                                if (exec) {
-                                    out.write(ch);
-                                }
-                                break;
-                            default:
-                                throw new IllegalArgumentException();
-                        }
-                    }
-                    break;
-                case '^':
-                    ch = str.charAt(index++);
-                    if (exec) {
-                        out.write(ch - '@');
-                    }
-                    break;
-                case '%':
-                    ch = str.charAt(index++);
-                    switch (ch) {
-                        case '%':
-                            if (exec) {
-                                out.write('%');
-                            }
-                            break;
-                        case 'p':
-                            ch = str.charAt(index++);
-                            if (exec) {
-                                stack.push(params[ch - '1']);
-                            }
-                            break;
-                        case 'P':
-                            ch = str.charAt(index++);
-                            if (ch >= 'a' && ch <= 'z') {
-                                if (exec) {
-                                    dv[ch - 'a'] = stack.pop();
-                                }
-                            } else if (ch >= 'A' && ch <= 'Z') {
-                                if (exec) {
-                                    sv[ch - 'A'] = stack.pop();
-                                }
-                            } else {
-                                throw new IllegalArgumentException();
-                            }
-                            break;
-                        case 'g':
-                            ch = str.charAt(index++);
-                            if (ch >= 'a' && ch <= 'z') {
-                                if (exec) {
-                                    stack.push(dv[ch - 'a']);
-                                }
-                            } else if (ch >= 'A' && ch <= 'Z') {
-                                if (exec) {
-                                    stack.push(sv[ch - 'A']);
-                                }
-                            } else {
-                                throw new IllegalArgumentException();
-                            }
-                            break;
-                        case '\'':
-                            ch = str.charAt(index++);
-                            if (exec) {
-                                stack.push((int) ch);
-                            }
-                            ch = str.charAt(index++);
-                            if (ch != '\'') {
-                                throw new IllegalArgumentException();
-                            }
-                            break;
-                        case '{':
-                            int start = index;
-                            while (str.charAt(index++) != '}') ;
-                            if (exec) {
-                                int v = Integer.valueOf(str.substring(start, index - 1));
-                                stack.push(v);
-                            }
-                            break;
-                        case 'l':
-                            if (exec) {
-                                stack.push(stack.pop().toString().length());
-                            }
-                            break;
-                        case '+':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 + v2);
-                            }
-                            break;
-                        case '-':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 - v2);
-                            }
-                            break;
-                        case '*':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 * v2);
-                            }
-                            break;
-                        case '/':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 / v2);
-                            }
-                            break;
-                        case 'm':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 % v2);
-                            }
-                            break;
-                        case '&':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 & v2);
-                            }
-                            break;
-                        case '|':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 | v2);
-                            }
-                            break;
-                        case '^':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 ^ v2);
-                            }
-                            break;
-                        case '=':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 == v2);
-                            }
-                            break;
-                        case '>':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 > v2);
-                            }
-                            break;
-                        case '<':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 < v2);
-                            }
-                            break;
-                        case 'A':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 != 0 && v2 != 0);
-                            }
-                            break;
-                        case '!':
-                            if (exec) {
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 == 0);
-                            }
-                            break;
-                        case '~':
-                            if (exec) {
-                                int v1 = toInteger(stack.pop());
-                                stack.push(~v1);
-                            }
-                            break;
-                        case 'O':
-                            if (exec) {
-                                int v2 = toInteger(stack.pop());
-                                int v1 = toInteger(stack.pop());
-                                stack.push(v1 != 0 || v2 != 0);
-                            }
-                            break;
-                        case '?':
-                            if (ifte != IFTE_NONE) {
-                                throw new IllegalArgumentException();
-                            } else {
-                                ifte = IFTE_IF;
-                            }
-                            break;
-                        case 't':
-                            if (ifte != IFTE_IF && ifte != IFTE_ELSE) {
-                                throw new IllegalArgumentException();
-                            } else {
-                                ifte = IFTE_THEN;
-                            }
-                            exec = toInteger(stack.pop()) != 0;
-                            break;
-                        case 'e':
-                            if (ifte != IFTE_THEN) {
-                                throw new IllegalArgumentException();
-                            } else {
-                                ifte = IFTE_ELSE;
-                            }
-                            exec = !exec;
-                            break;
-                        case ';':
-                            if (ifte == IFTE_NONE || ifte == IFTE_IF) {
-                                throw new IllegalArgumentException();
-                            } else {
-                                ifte = IFTE_NONE;
-                            }
-                            exec = true;
-                            break;
-                        case 'i':
-                            if (params.length >= 1) {
-                                params[0] = toInteger(params[0]) + 1;
-                            }
-                            if (params.length >= 2) {
-                                params[1] = toInteger(params[1]) + 1;
-                            }
-                            break;
-                        case 'd':
-                            out.write(Integer.toString(toInteger(stack.pop())));
-                            break;
-                        default:
-                            throw new UnsupportedOperationException();
-                    }
-                    break;
-                default:
-                    if (exec) {
-                        out.write(ch);
-                    }
-                    break;
-            }
-        }
-    }
-
-    private static int toInteger(Object pop) {
-        if (pop instanceof Number) {
-            return ((Number) pop).intValue();
-        } else if (pop instanceof Boolean) {
-            return (Boolean) pop ? 1 : 0;
-        } else {
-            return Integer.valueOf(pop.toString());
-        }
-    }
-
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InfoCmp.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,591 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Infocmp helper methods.
- *
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- */
-public class InfoCmp {
-
-    private static final Map<String, String> CAPS = new HashMap<String, String>();
-
-    public static String getInfoCmp(
-            String terminal
-    ) throws IOException, InterruptedException {
-        String caps = CAPS.get(terminal);
-        if (caps == null) {
-            Process p = new ProcessBuilder("infocmp", terminal).start();
-            caps = TerminalLineSettings.waitAndCapture(p);
-            CAPS.put(terminal, caps);
-        }
-        return caps;
-    }
-
-    public static String getAnsiCaps() {
-        return ANSI_CAPS;
-    }
-
-    public static void parseInfoCmp(
-            String capabilities,
-            Set<String> bools,
-            Map<String, Integer> ints,
-            Map<String, String> strings
-    ) {
-        String[] lines = capabilities.split("\n");
-        for (int i = 2; i < lines.length; i++) {
-            Matcher m = Pattern.compile("\\s*(([^,]|\\\\,)+)\\s*[,$]").matcher(lines[i]);
-            while (m.find()) {
-                String cap = m.group(1);
-                if (cap.contains("#")) {
-                    int index = cap.indexOf('#');
-                    String key = cap.substring(0, index);
-                    String val = cap.substring(index + 1);
-                    int iVal;
-                    if (val.startsWith("0x")) {
-                        iVal = Integer.parseInt(val.substring(2), 16);
-                    } else {
-                        iVal = Integer.parseInt(val);
-                    }
-                    for (String name : getNames(key)) {
-                        ints.put(name, iVal);
-                    }
-                } else if (cap.contains("=")) {
-                    int index = cap.indexOf('=');
-                    String key = cap.substring(0, index);
-                    String val = cap.substring(index + 1);
-                    for (String name : getNames(key)) {
-                        strings.put(name, val);
-                    }
-                } else {
-                    for (String name : getNames(cap)) {
-                        bools.add(name);
-                    }
-                }
-            }
-        }
-    }
-
-    public static String[] getNames(String name) {
-        String[] names = NAMES.get(name);
-        return names != null ? names : new String[] { name };
-    }
-
-    private static final Map<String, String[]> NAMES;
-    static {
-        String[][] list = {
-                { "auto_left_margin", "bw", "bw" },
-                { "auto_right_margin", "am", "am" },
-                { "back_color_erase", "bce", "ut" },
-                { "can_change", "ccc", "cc" },
-                { "ceol_standout_glitch", "xhp", "xs" },
-                { "col_addr_glitch", "xhpa", "YA" },
-                { "cpi_changes_res", "cpix", "YF" },
-                { "cr_cancels_micro_mode", "crxm", "YB" },
-                { "dest_tabs_magic_smso", "xt", "xt" },
-                { "eat_newline_glitch", "xenl", "xn" },
-                { "erase_overstrike", "eo", "eo" },
-                { "generic_type", "gn", "gn" },
-                { "hard_copy", "hc", "hc" },
-                { "hard_cursor", "chts", "HC" },
-                { "has_meta_key", "km", "km" },
-                { "has_print_wheel", "daisy", "YC" },
-                { "has_status_line", "hs", "hs" },
-                { "hue_lightness_saturation", "hls", "hl" },
-                { "insert_null_glitch", "in", "in" },
-                { "lpi_changes_res", "lpix", "YG" },
-                { "memory_above", "da", "da" },
-                { "memory_below", "db", "db" },
-                { "move_insert_mode", "mir", "mi" },
-                { "move_standout_mode", "msgr", "ms" },
-                { "needs_xon_xoff", "nxon", "nx" },
-                { "no_esc_ctlc", "xsb", "xb" },
-                { "no_pad_char", "npc", "NP" },
-                { "non_dest_scroll_region", "ndscr", "ND" },
-                { "non_rev_rmcup", "nrrmc", "NR" },
-                { "over_strike", "os", "os" },
-                { "prtr_silent", "mc5i", "5i" },
-                { "row_addr_glitch", "xvpa", "YD" },
-                { "semi_auto_right_margin", "sam", "YE" },
-                { "status_line_esc_ok", "eslok", "es" },
-                { "tilde_glitch", "hz", "hz" },
-                { "transparent_underline", "ul", "ul" },
-                { "xon_xoff", "xon", "xo" },
-                { "columns", "cols", "co" },
-                { "init_tabs", "it", "it" },
-                { "label_height", "lh", "lh" },
-                { "label_width", "lw", "lw" },
-                { "lines", "lines", "li" },
-                { "lines_of_memory", "lm", "lm" },
-                { "magic_cookie_glitch", "xmc", "sg" },
-                { "max_attributes", "ma", "ma" },
-                { "max_colors", "colors", "Co" },
-                { "max_pairs", "pairs", "pa" },
-                { "maximum_windows", "wnum", "MW" },
-                { "no_color_video", "ncv", "NC" },
-                { "num_labels", "nlab", "Nl" },
-                { "padding_baud_rate", "pb", "pb" },
-                { "virtual_terminal", "vt", "vt" },
-                { "width_status_line", "wsl", "ws" },
-                { "bit_image_entwining", "bitwin", "Yo" },
-                { "bit_image_type", "bitype", "Yp" },
-                { "buffer_capacity", "bufsz", "Ya" },
-                { "buttons", "btns", "BT" },
-                { "dot_horz_spacing", "spinh", "Yc" },
-                { "dot_vert_spacing", "spinv", "Yb" },
-                { "max_micro_address", "maddr", "Yd" },
-                { "max_micro_jump", "mjump", "Ye" },
-                { "micro_col_size", "mcs", "Yf" },
-                { "micro_line_size", "mls", "Yg" },
-                { "number_of_pins", "npins", "Yh" },
-                { "output_res_char", "orc", "Yi" },
-                { "output_res_horz_inch", "orhi", "Yk" },
-                { "output_res_line", "orl", "Yj" },
-                { "output_res_vert_inch", "orvi", "Yl" },
-                { "print_rate", "cps", "Ym" },
-                { "wide_char_size", "widcs", "Yn" },
-                { "acs_chars", "acsc", "ac" },
-                { "back_tab", "cbt", "bt" },
-                { "bell", "bel", "bl" },
-                { "carriage_return", "cr", "cr" },
-                { "change_char_pitch", "cpi", "ZA" },
-                { "change_line_pitch", "lpi", "ZB" },
-                { "change_res_horz", "chr", "ZC" },
-                { "change_res_vert", "cvr", "ZD" },
-                { "change_scroll_region", "csr", "cs" },
-                { "char_padding", "rmp", "rP" },
-                { "clear_all_tabs", "tbc", "ct" },
-                { "clear_margins", "mgc", "MC" },
-                { "clear_screen", "clear", "cl" },
-                { "clr_bol", "el1", "cb" },
-                { "clr_eol", "el", "ce" },
-                { "clr_eos", "ed", "cd" },
-                { "column_address", "hpa", "ch" },
-                { "command_character", "cmdch", "CC" },
-                { "create_window", "cwin", "CW" },
-                { "cursor_address", "cup", "cm" },
-                { "cursor_down", "cud1", "do" },
-                { "cursor_home", "home", "ho" },
-                { "cursor_invisible", "civis", "vi" },
-                { "cursor_left", "cub1", "le" },
-                { "cursor_mem_address", "mrcup", "CM" },
-                { "cursor_normal", "cnorm", "ve" },
-                { "cursor_right", "cuf1", "nd" },
-                { "cursor_to_ll", "ll", "ll" },
-                { "cursor_up", "cuu1", "up" },
-                { "cursor_visible", "cvvis", "vs" },
-                { "define_char", "defc", "ZE" },
-                { "delete_character", "dch1", "dc" },
-                { "delete_line", "dl1", "dl" },
-                { "dial_phone", "dial", "DI" },
-                { "dis_status_line", "dsl", "ds" },
-                { "display_clock", "dclk", "DK" },
-                { "down_half_line", "hd", "hd" },
-                { "ena_acs", "enacs", "eA" },
-                { "enter_alt_charset_mode", "smacs", "as" },
-                { "enter_am_mode", "smam", "SA" },
-                { "enter_blink_mode", "blink", "mb" },
-                { "enter_bold_mode", "bold", "md" },
-                { "enter_ca_mode", "smcup", "ti" },
-                { "enter_delete_mode", "smdc", "dm" },
-                { "enter_dim_mode", "dim", "mh" },
-                { "enter_doublewide_mode", "swidm", "ZF" },
-                { "enter_draft_quality", "sdrfq", "ZG" },
-                { "enter_insert_mode", "smir", "im" },
-                { "enter_italics_mode", "sitm", "ZH" },
-                { "enter_leftward_mode", "slm", "ZI" },
-                { "enter_micro_mode", "smicm", "ZJ" },
-                { "enter_near_letter_quality", "snlq", "ZK" },
-                { "enter_normal_quality", "snrmq", "ZL" },
-                { "enter_protected_mode", "prot", "mp" },
-                { "enter_reverse_mode", "rev", "mr" },
-                { "enter_secure_mode", "invis", "mk" },
-                { "enter_shadow_mode", "sshm", "ZM" },
-                { "enter_standout_mode", "smso", "so" },
-                { "enter_subscript_mode", "ssubm", "ZN" },
-                { "enter_superscript_mode", "ssupm", "ZO" },
-                { "enter_underline_mode", "smul", "us" },
-                { "enter_upward_mode", "sum", "ZP" },
-                { "enter_xon_mode", "smxon", "SX" },
-                { "erase_chars", "ech", "ec" },
-                { "exit_alt_charset_mode", "rmacs", "ae" },
-                { "exit_am_mode", "rmam", "RA" },
-                { "exit_attribute_mode", "sgr0", "me" },
-                { "exit_ca_mode", "rmcup", "te" },
-                { "exit_delete_mode", "rmdc", "ed" },
-                { "exit_doublewide_mode", "rwidm", "ZQ" },
-                { "exit_insert_mode", "rmir", "ei" },
-                { "exit_italics_mode", "ritm", "ZR" },
-                { "exit_leftward_mode", "rlm", "ZS" },
-                { "exit_micro_mode", "rmicm", "ZT" },
-                { "exit_shadow_mode", "rshm", "ZU" },
-                { "exit_standout_mode", "rmso", "se" },
-                { "exit_subscript_mode", "rsubm", "ZV" },
-                { "exit_superscript_mode", "rsupm", "ZW" },
-                { "exit_underline_mode", "rmul", "ue" },
-                { "exit_upward_mode", "rum", "ZX" },
-                { "exit_xon_mode", "rmxon", "RX" },
-                { "fixed_pause", "pause", "PA" },
-                { "flash_hook", "hook", "fh" },
-                { "flash_screen", "flash", "vb" },
-                { "form_feed", "ff", "ff" },
-                { "from_status_line", "fsl", "fs" },
-                { "goto_window", "wingo", "WG" },
-                { "hangup", "hup", "HU" },
-                { "init_1string", "is1", "i1" },
-                { "init_2string", "is2", "is" },
-                { "init_3string", "is3", "i3" },
-                { "init_file", "if", "if" },
-                { "init_prog", "iprog", "iP" },
-                { "initialize_color", "initc", "Ic" },
-                { "initialize_pair", "initp", "Ip" },
-                { "insert_character", "ich1", "ic" },
-                { "insert_line", "il1", "al" },
-                { "insert_padding", "ip", "ip" },
-                { "key_a1", "ka1", "K1" },
-                { "key_a3", "ka3", "K3" },
-                { "key_b2", "kb2", "K2" },
-                { "key_backspace", "kbs", "kb" },
-                { "key_beg", "kbeg", "@1" },
-                { "key_btab", "kcbt", "kB" },
-                { "key_c1", "kc1", "K4" },
-                { "key_c3", "kc3", "K5" },
-                { "key_cancel", "kcan", "@2" },
-                { "key_catab", "ktbc", "ka" },
-                { "key_clear", "kclr", "kC" },
-                { "key_close", "kclo", "@3" },
-                { "key_command", "kcmd", "@4" },
-                { "key_copy", "kcpy", "@5" },
-                { "key_create", "kcrt", "@6" },
-                { "key_ctab", "kctab", "kt" },
-                { "key_dc", "kdch1", "kD" },
-                { "key_dl", "kdl1", "kL" },
-                { "key_down", "kcud1", "kd" },
-                { "key_eic", "krmir", "kM" },
-                { "key_end", "kend", "@7" },
-                { "key_enter", "kent", "@8" },
-                { "key_eol", "kel", "kE" },
-                { "key_eos", "ked", "kS" },
-                { "key_exit", "kext", "@9" },
-                { "key_f0", "kf0", "k0" },
-                { "key_f1", "kf1", "k1" },
-                { "key_f10", "kf10", "k;" },
-                { "key_f11", "kf11", "F1" },
-                { "key_f12", "kf12", "F2" },
-                { "key_f13", "kf13", "F3" },
-                { "key_f14", "kf14", "F4" },
-                { "key_f15", "kf15", "F5" },
-                { "key_f16", "kf16", "F6" },
-                { "key_f17", "kf17", "F7" },
-                { "key_f18", "kf18", "F8" },
-                { "key_f19", "kf19", "F9" },
-                { "key_f2", "kf2", "k2" },
-                { "key_f20", "kf20", "FA" },
-                { "key_f21", "kf21", "FB" },
-                { "key_f22", "kf22", "FC" },
-                { "key_f23", "kf23", "FD" },
-                { "key_f24", "kf24", "FE" },
-                { "key_f25", "kf25", "FF" },
-                { "key_f26", "kf26", "FG" },
-                { "key_f27", "kf27", "FH" },
-                { "key_f28", "kf28", "FI" },
-                { "key_f29", "kf29", "FJ" },
-                { "key_f3", "kf3", "k3" },
-                { "key_f30", "kf30", "FK" },
-                { "key_f31", "kf31", "FL" },
-                { "key_f32", "kf32", "FM" },
-                { "key_f33", "kf33", "FN" },
-                { "key_f34", "kf34", "FO" },
-                { "key_f35", "kf35", "FP" },
-                { "key_f36", "kf36", "FQ" },
-                { "key_f37", "kf37", "FR" },
-                { "key_f38", "kf38", "FS" },
-                { "key_f39", "kf39", "FT" },
-                { "key_f4", "kf4", "k4" },
-                { "key_f40", "kf40", "FU" },
-                { "key_f41", "kf41", "FV" },
-                { "key_f42", "kf42", "FW" },
-                { "key_f43", "kf43", "FX" },
-                { "key_f44", "kf44", "FY" },
-                { "key_f45", "kf45", "FZ" },
-                { "key_f46", "kf46", "Fa" },
-                { "key_f47", "kf47", "Fb" },
-                { "key_f48", "kf48", "Fc" },
-                { "key_f49", "kf49", "Fd" },
-                { "key_f5", "kf5", "k5" },
-                { "key_f50", "kf50", "Fe" },
-                { "key_f51", "kf51", "Ff" },
-                { "key_f52", "kf52", "Fg" },
-                { "key_f53", "kf53", "Fh" },
-                { "key_f54", "kf54", "Fi" },
-                { "key_f55", "kf55", "Fj" },
-                { "key_f56", "kf56", "Fk" },
-                { "key_f57", "kf57", "Fl" },
-                { "key_f58", "kf58", "Fm" },
-                { "key_f59", "kf59", "Fn" },
-                { "key_f6", "kf6", "k6" },
-                { "key_f60", "kf60", "Fo" },
-                { "key_f61", "kf61", "Fp" },
-                { "key_f62", "kf62", "Fq" },
-                { "key_f63", "kf63", "Fr" },
-                { "key_f7", "kf7", "k7" },
-                { "key_f8", "kf8", "k8" },
-                { "key_f9", "kf9", "k9" },
-                { "key_find", "kfnd", "@0" },
-                { "key_help", "khlp", "%1" },
-                { "key_home", "khome", "kh" },
-                { "key_ic", "kich1", "kI" },
-                { "key_il", "kil1", "kA" },
-                { "key_left", "kcub1", "kl" },
-                { "key_ll", "kll", "kH" },
-                { "key_mark", "kmrk", "%2" },
-                { "key_message", "kmsg", "%3" },
-                { "key_move", "kmov", "%4" },
-                { "key_next", "knxt", "%5" },
-                { "key_npage", "knp", "kN" },
-                { "key_open", "kopn", "%6" },
-                { "key_options", "kopt", "%7" },
-                { "key_ppage", "kpp", "kP" },
-                { "key_previous", "kprv", "%8" },
-                { "key_print", "kprt", "%9" },
-                { "key_redo", "krdo", "%0" },
-                { "key_reference", "kref", "&1" },
-                { "key_refresh", "krfr", "&2" },
-                { "key_replace", "krpl", "&3" },
-                { "key_restart", "krst", "&4" },
-                { "key_resume", "kres", "&5" },
-                { "key_right", "kcuf1", "kr" },
-                { "key_save", "ksav", "&6" },
-                { "key_sbeg", "kBEG", "&9" },
-                { "key_scancel", "kCAN", "&0" },
-                { "key_scommand", "kCMD", "*1" },
-                { "key_scopy", "kCPY", "*2" },
-                { "key_screate", "kCRT", "*3" },
-                { "key_sdc", "kDC", "*4" },
-                { "key_sdl", "kDL", "*5" },
-                { "key_select", "kslt", "*6" },
-                { "key_send", "kEND", "*7" },
-                { "key_seol", "kEOL", "*8" },
-                { "key_sexit", "kEXT", "*9" },
-                { "key_sf", "kind", "kF" },
-                { "key_sfind", "kFND", "*0" },
-                { "key_shelp", "kHLP", "#1" },
-                { "key_shome", "kHOM", "#2" },
-                { "key_sic", "kIC", "#3" },
-                { "key_sleft", "kLFT", "#4" },
-                { "key_smessage", "kMSG", "%a" },
-                { "key_smove", "kMOV", "%b" },
-                { "key_snext", "kNXT", "%c" },
-                { "key_soptions", "kOPT", "%d" },
-                { "key_sprevious", "kPRV", "%e" },
-                { "key_sprint", "kPRT", "%f" },
-                { "key_sr", "kri", "kR" },
-                { "key_sredo", "kRDO", "%g" },
-                { "key_sreplace", "kRPL", "%h" },
-                { "key_sright", "kRIT", "%i" },
-                { "key_srsume", "kRES", "%j" },
-                { "key_ssave", "kSAV", "!1" },
-                { "key_ssuspend", "kSPD", "!2" },
-                { "key_stab", "khts", "kT" },
-                { "key_sundo", "kUND", "!3" },
-                { "key_suspend", "kspd", "&7" },
-                { "key_undo", "kund", "&8" },
-                { "key_up", "kcuu1", "ku" },
-                { "keypad_local", "rmkx", "ke" },
-                { "keypad_xmit", "smkx", "ks" },
-                { "lab_f0", "lf0", "l0" },
-                { "lab_f1", "lf1", "l1" },
-                { "lab_f10", "lf10", "la" },
-                { "lab_f2", "lf2", "l2" },
-                { "lab_f3", "lf3", "l3" },
-                { "lab_f4", "lf4", "l4" },
-                { "lab_f5", "lf5", "l5" },
-                { "lab_f6", "lf6", "l6" },
-                { "lab_f7", "lf7", "l7" },
-                { "lab_f8", "lf8", "l8" },
-                { "lab_f9", "lf9", "l9" },
-                { "label_format", "fln", "Lf" },
-                { "label_off", "rmln", "LF" },
-                { "label_on", "smln", "LO" },
-                { "meta_off", "rmm", "mo" },
-                { "meta_on", "smm", "mm" },
-                { "micro_column_address", "mhpa", "ZY" },
-                { "micro_down", "mcud1", "ZZ" },
-                { "micro_left", "mcub1", "Za" },
-                { "micro_right", "mcuf1", "Zb" },
-                { "micro_row_address", "mvpa", "Zc" },
-                { "micro_up", "mcuu1", "Zd" },
-                { "newline", "nel", "nw" },
-                { "order_of_pins", "porder", "Ze" },
-                { "orig_colors", "oc", "oc" },
-                { "orig_pair", "op", "op" },
-                { "pad_char", "pad", "pc" },
-                { "parm_dch", "dch", "DC" },
-                { "parm_delete_line", "dl", "DL" },
-                { "parm_down_cursor", "cud", "DO" },
-                { "parm_down_micro", "mcud", "Zf" },
-                { "parm_ich", "ich", "IC" },
-                { "parm_index", "indn", "SF" },
-                { "parm_insert_line", "il", "AL" },
-                { "parm_left_cursor", "cub", "LE" },
-                { "parm_left_micro", "mcub", "Zg" },
-                { "parm_right_cursor", "cuf", "RI" },
-                { "parm_right_micro", "mcuf", "Zh" },
-                { "parm_rindex", "rin", "SR" },
-                { "parm_up_cursor", "cuu", "UP" },
-                { "parm_up_micro", "mcuu", "Zi" },
-                { "pkey_key", "pfkey", "pk" },
-                { "pkey_local", "pfloc", "pl" },
-                { "pkey_xmit", "pfx", "px" },
-                { "plab_norm", "pln", "pn" },
-                { "print_screen", "mc0", "ps" },
-                { "prtr_non", "mc5p", "pO" },
-                { "prtr_off", "mc4", "pf" },
-                { "prtr_on", "mc5", "po" },
-                { "pulse", "pulse", "PU" },
-                { "quick_dial", "qdial", "QD" },
-                { "remove_clock", "rmclk", "RC" },
-                { "repeat_char", "rep", "rp" },
-                { "req_for_input", "rfi", "RF" },
-                { "reset_1string", "rs1", "r1" },
-                { "reset_2string", "rs2", "r2" },
-                { "reset_3string", "rs3", "r3" },
-                { "reset_file", "rf", "rf" },
-                { "restore_cursor", "rc", "rc" },
-                { "row_address", "vpa", "cv" },
-                { "save_cursor", "sc", "sc" },
-                { "scroll_forward", "ind", "sf" },
-                { "scroll_reverse", "ri", "sr" },
-                { "select_char_set", "scs", "Zj" },
-                { "set_attributes", "sgr", "sa" },
-                { "set_background", "setb", "Sb" },
-                { "set_bottom_margin", "smgb", "Zk" },
-                { "set_bottom_margin_parm", "smgbp", "Zl" },
-                { "set_clock", "sclk", "SC" },
-                { "set_color_pair", "scp", "sp" },
-                { "set_foreground", "setf", "Sf" },
-                { "set_left_margin", "smgl", "ML" },
-                { "set_left_margin_parm", "smglp", "Zm" },
-                { "set_right_margin", "smgr", "MR" },
-                { "set_right_margin_parm", "smgrp", "Zn" },
-                { "set_tab", "hts", "st" },
-                { "set_top_margin", "smgt", "Zo" },
-                { "set_top_margin_parm", "smgtp", "Zp" },
-                { "set_window", "wind", "wi" },
-                { "start_bit_image", "sbim", "Zq" },
-                { "start_char_set_def", "scsd", "Zr" },
-                { "stop_bit_image", "rbim", "Zs" },
-                { "stop_char_set_def", "rcsd", "Zt" },
-                { "subscript_characters", "subcs", "Zu" },
-                { "superscript_characters", "supcs", "Zv" },
-                { "tab", "ht", "ta" },
-                { "these_cause_cr", "docr", "Zw" },
-                { "to_status_line", "tsl", "ts" },
-                { "tone", "tone", "TO" },
-                { "underline_char", "uc", "uc" },
-                { "up_half_line", "hu", "hu" },
-                { "user0", "u0", "u0" },
-                { "user1", "u1", "u1" },
-                { "user2", "u2", "u2" },
-                { "user3", "u3", "u3" },
-                { "user4", "u4", "u4" },
-                { "user5", "u5", "u5" },
-                { "user6", "u6", "u6" },
-                { "user7", "u7", "u7" },
-                { "user8", "u8", "u8" },
-                { "user9", "u9", "u9" },
-                { "wait_tone", "wait", "WA" },
-                { "xoff_character", "xoffc", "XF" },
-                { "xon_character", "xonc", "XN" },
-                { "zero_motion", "zerom", "Zx" },
-                { "alt_scancode_esc", "scesa", "S8" },
-                { "bit_image_carriage_return", "bicr", "Yv" },
-                { "bit_image_newline", "binel", "Zz" },
-                { "bit_image_repeat", "birep", "Xy" },
-                { "char_set_names", "csnm", "Zy" },
-                { "code_set_init", "csin", "ci" },
-                { "color_names", "colornm", "Yw" },
-                { "define_bit_image_region", "defbi", "Yx" },
-                { "device_type", "devt", "dv" },
-                { "display_pc_char", "dispc", "S1" },
-                { "end_bit_image_region", "endbi", "Yy" },
-                { "enter_pc_charset_mode", "smpch", "S2" },
-                { "enter_scancode_mode", "smsc", "S4" },
-                { "exit_pc_charset_mode", "rmpch", "S3" },
-                { "exit_scancode_mode", "rmsc", "S5" },
-                { "get_mouse", "getm", "Gm" },
-                { "key_mouse", "kmous", "Km" },
-                { "mouse_info", "minfo", "Mi" },
-                { "pc_term_options", "pctrm", "S6" },
-                { "pkey_plab", "pfxl", "xl" },
-                { "req_mouse_pos", "reqmp", "RQ" },
-                { "scancode_escape", "scesc", "S7" },
-                { "set0_des_seq", "s0ds", "s0" },
-                { "set1_des_seq", "s1ds", "s1" },
-                { "set2_des_seq", "s2ds", "s2" },
-                { "set3_des_seq", "s3ds", "s3" },
-                { "set_a_background", "setab", "AB" },
-                { "set_a_foreground", "setaf", "AF" },
-                { "set_color_band", "setcolor", "Yz" },
-                { "set_lr_margin", "smglr", "ML" },
-                { "set_page_length", "slines", "YZ" },
-                { "set_tb_margin", "smgtb", "MT" },
-                { "enter_horizontal_hl_mode", "ehhlm", "Xh" },
-                { "enter_left_hl_mode", "elhlm", "Xl" },
-                { "enter_low_hl_mode", "elohlm", "Xo" },
-                { "enter_right_hl_mode", "erhlm", "Xr" },
-                { "enter_top_hl_mode", "ethlm", "Xt" },
-                { "enter_vertical_hl_mode", "evhlm", "Xv" },
-                { "set_a_attributes", "sgr1", "sA" },
-                { "set_pglen_inch", "slength", "sL" }
-        };
-
-        Map<String, String[]> map = new HashMap<String, String[]>();
-        for (String[] names : list) {
-            for (String name : names) {
-                map.put(name, names);
-            }
-        }
-        NAMES = Collections.unmodifiableMap(map);
-    }
-
-    private static String ANSI_CAPS =
-            "#\tReconstructed via infocmp from file: /usr/share/terminfo/61/ansi\n" +
-            "ansi|ansi/pc-term compatible with color,\n" +
-            "\tam, mc5i, mir, msgr,\n" +
-            "\tcolors#8, cols#80, it#8, lines#24, ncv#3, pairs#64,\n" +
-            "\tacsc=+\\020\\,\\021-\\030.^Y0\\333`\\004a\\261f\\370g\\361h\\260j\\331k\\277l\\332m\\300n\\305o~p\\304q\\304r\\304s_t\\303u\\264v\\301w\\302x\\263y\\363z\\362{\\343|\\330}\\234~\\376,\n" +
-            "\tbel=^G, blink=\\E[5m, bold=\\E[1m, cbt=\\E[Z, clear=\\E[H\\E[J,\n" +
-            "\tcr=^M, cub=\\E[%p1%dD, cub1=\\E[D, cud=\\E[%p1%dB, cud1=\\E[B,\n" +
-            "\tcuf=\\E[%p1%dC, cuf1=\\E[C, cup=\\E[%i%p1%d;%p2%dH,\n" +
-            "\tcuu=\\E[%p1%dA, cuu1=\\E[A, dch=\\E[%p1%dP, dch1=\\E[P,\n" +
-            "\tdl=\\E[%p1%dM, dl1=\\E[M, ech=\\E[%p1%dX, ed=\\E[J, el=\\E[K,\n" +
-            "\tel1=\\E[1K, home=\\E[H, hpa=\\E[%i%p1%dG, ht=\\E[I, hts=\\EH,\n" +
-            "\tich=\\E[%p1%d@, il=\\E[%p1%dL, il1=\\E[L, ind=^J,\n" +
-            "\tindn=\\E[%p1%dS, invis=\\E[8m, kbs=^H, kcbt=\\E[Z, kcub1=\\E[D,\n" +
-            "\tkcud1=\\E[B, kcuf1=\\E[C, kcuu1=\\E[A, khome=\\E[H, kich1=\\E[L,\n" +
-            "\tmc4=\\E[4i, mc5=\\E[5i, nel=\\r\\E[S, op=\\E[39;49m,\n" +
-            "\trep=%p1%c\\E[%p2%{1}%-%db, rev=\\E[7m, rin=\\E[%p1%dT,\n" +
-            "\trmacs=\\E[10m, rmpch=\\E[10m, rmso=\\E[m, rmul=\\E[m,\n" +
-            "\ts0ds=\\E(B, s1ds=\\E)B, s2ds=\\E*B, s3ds=\\E+B,\n" +
-            "\tsetab=\\E[4%p1%dm, setaf=\\E[3%p1%dm,\n" +
-            "\tsgr=\\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,\n" +
-            "\tsgr0=\\E[0;10m, smacs=\\E[11m, smpch=\\E[11m, smso=\\E[7m,\n" +
-            "\tsmul=\\E[4m, tbc=\\E[2g, u6=\\E[%i%d;%dR, u7=\\E[6n,\n" +
-            "\tu8=\\E[?%[;0123456789]c, u9=\\E[c, vpa=\\E[%i%p1%dd,";
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InputStreamReader.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,334 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.MalformedInputException;
-import java.nio.charset.UnmappableCharacterException;
-
-
-/**
- *
- * NOTE for JLine: the default InputStreamReader that comes from the JRE
- * usually read more bytes than needed from the input stream, which
- * is not usable in a character per character model used in the console.
- * We thus use the harmony code which only reads the minimal number of bytes,
- * with a modification to ensure we can read larger characters (UTF-16 has
- * up to 4 bytes, and UTF-32, rare as it is, may have up to 8).
- */
-/**
- * A class for turning a byte stream into a character stream. Data read from the
- * source input stream is converted into characters by either a default or a
- * provided character converter. The default encoding is taken from the
- * "file.encoding" system property. {@code InputStreamReader} contains a buffer
- * of bytes read from the source stream and converts these into characters as
- * needed. The buffer size is 8K.
- *
- * @see OutputStreamWriter
- */
-public class InputStreamReader extends Reader {
-    private InputStream in;
-
-    private static final int BUFFER_SIZE = 8192;
-
-    private boolean endOfInput = false;
-
-    CharsetDecoder decoder;
-
-    ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
-
-    /**
-     * Constructs a new {@code InputStreamReader} on the {@link InputStream}
-     * {@code in}. This constructor sets the character converter to the encoding
-     * specified in the "file.encoding" property and falls back to ISO 8859_1
-     * (ISO-Latin-1) if the property doesn't exist.
-     *
-     * @param in
-     *            the input stream from which to read characters.
-     */
-    public InputStreamReader(InputStream in) {
-        super(in);
-        this.in = in;
-        decoder = Charset.defaultCharset().newDecoder().onMalformedInput(
-                CodingErrorAction.REPLACE).onUnmappableCharacter(
-                CodingErrorAction.REPLACE);
-        bytes.limit(0);
-    }
-
-    /**
-     * Constructs a new InputStreamReader on the InputStream {@code in}. The
-     * character converter that is used to decode bytes into characters is
-     * identified by name by {@code enc}. If the encoding cannot be found, an
-     * UnsupportedEncodingException error is thrown.
-     *
-     * @param in
-     *            the InputStream from which to read characters.
-     * @param enc
-     *            identifies the character converter to use.
-     * @throws NullPointerException
-     *             if {@code enc} is {@code null}.
-     * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code enc} cannot be found.
-     */
-    public InputStreamReader(InputStream in, final String enc)
-            throws UnsupportedEncodingException {
-        super(in);
-        if (enc == null) {
-            throw new NullPointerException();
-        }
-        this.in = in;
-        try {
-            decoder = Charset.forName(enc).newDecoder().onMalformedInput(
-                    CodingErrorAction.REPLACE).onUnmappableCharacter(
-                    CodingErrorAction.REPLACE);
-        } catch (IllegalArgumentException e) {
-            throw (UnsupportedEncodingException)
-                    new UnsupportedEncodingException(enc).initCause(e);
-        }
-        bytes.limit(0);
-    }
-
-    /**
-     * Constructs a new InputStreamReader on the InputStream {@code in} and
-     * CharsetDecoder {@code dec}.
-     *
-     * @param in
-     *            the source InputStream from which to read characters.
-     * @param dec
-     *            the CharsetDecoder used by the character conversion.
-     */
-    public InputStreamReader(InputStream in, CharsetDecoder dec) {
-        super(in);
-        dec.averageCharsPerByte();
-        this.in = in;
-        decoder = dec;
-        bytes.limit(0);
-    }
-
-    /**
-     * Constructs a new InputStreamReader on the InputStream {@code in} and
-     * Charset {@code charset}.
-     *
-     * @param in
-     *            the source InputStream from which to read characters.
-     * @param charset
-     *            the Charset that defines the character converter
-     */
-    public InputStreamReader(InputStream in, Charset charset) {
-        super(in);
-        this.in = in;
-        decoder = charset.newDecoder().onMalformedInput(
-                CodingErrorAction.REPLACE).onUnmappableCharacter(
-                CodingErrorAction.REPLACE);
-        bytes.limit(0);
-    }
-
-    /**
-     * Closes this reader. This implementation closes the source InputStream and
-     * releases all local storage.
-     *
-     * @throws IOException
-     *             if an error occurs attempting to close this reader.
-     */
-    @Override
-    public void close() throws IOException {
-        synchronized (lock) {
-            decoder = null;
-            if (in != null) {
-                in.close();
-                in = null;
-            }
-        }
-    }
-
-    /**
-     * Returns the name of the encoding used to convert bytes into characters.
-     * The value {@code null} is returned if this reader has been closed.
-     *
-     * @return the name of the character converter or {@code null} if this
-     *         reader is closed.
-     */
-    public String getEncoding() {
-        if (!isOpen()) {
-            return null;
-        }
-        return decoder.charset().name();
-    }
-
-    /**
-     * Reads a single character from this reader and returns it as an integer
-     * with the two higher-order bytes set to 0. Returns -1 if the end of the
-     * reader has been reached. The byte value is either obtained from
-     * converting bytes in this reader's buffer or by first filling the buffer
-     * from the source InputStream and then reading from the buffer.
-     *
-     * @return the character read or -1 if the end of the reader has been
-     *         reached.
-     * @throws IOException
-     *             if this reader is closed or some other I/O error occurs.
-     */
-    @Override
-    public int read() throws IOException {
-        synchronized (lock) {
-            if (!isOpen()) {
-                throw new IOException("InputStreamReader is closed.");
-            }
-
-            char buf[] = new char[4];
-            return read(buf, 0, 4) != -1 ? Character.codePointAt(buf, 0) : -1;
-        }
-    }
-
-    /**
-     * Reads at most {@code length} characters from this reader and stores them
-     * at position {@code offset} in the character array {@code buf}. Returns
-     * the number of characters actually read or -1 if the end of the reader has
-     * been reached. The bytes are either obtained from converting bytes in this
-     * reader's buffer or by first filling the buffer from the source
-     * InputStream and then reading from the buffer.
-     *
-     * @param buf
-     *            the array to store the characters read.
-     * @param offset
-     *            the initial position in {@code buf} to store the characters
-     *            read from this reader.
-     * @param length
-     *            the maximum number of characters to read.
-     * @return the number of characters read or -1 if the end of the reader has
-     *         been reached.
-     * @throws IndexOutOfBoundsException
-     *             if {@code offset < 0} or {@code length < 0}, or if
-     *             {@code offset + length} is greater than the length of
-     *             {@code buf}.
-     * @throws IOException
-     *             if this reader is closed or some other I/O error occurs.
-     */
-    @Override
-    public int read(char[] buf, int offset, int length) throws IOException {
-        synchronized (lock) {
-            if (!isOpen()) {
-                throw new IOException("InputStreamReader is closed.");
-            }
-            if (offset < 0 || offset > buf.length - length || length < 0) {
-                throw new IndexOutOfBoundsException();
-            }
-            if (length == 0) {
-                return 0;
-            }
-
-            CharBuffer out = CharBuffer.wrap(buf, offset, length);
-            CoderResult result = CoderResult.UNDERFLOW;
-
-            // bytes.remaining() indicates number of bytes in buffer
-            // when 1-st time entered, it'll be equal to zero
-            boolean needInput = !bytes.hasRemaining();
-
-            while (out.hasRemaining()) {
-                // fill the buffer if needed
-                if (needInput) {
-                    try {
-                        if ((in.available() == 0)
-                            && (out.position() > offset)) {
-                            // we could return the result without blocking read
-                            break;
-                        }
-                    } catch (IOException e) {
-                        // available didn't work so just try the read
-                    }
-
-                    int to_read = bytes.capacity() - bytes.limit();
-                    int off = bytes.arrayOffset() + bytes.limit();
-                    int was_red = in.read(bytes.array(), off, to_read);
-
-                    if (was_red == -1) {
-                        endOfInput = true;
-                        break;
-                    } else if (was_red == 0) {
-                        break;
-                    }
-                    bytes.limit(bytes.limit() + was_red);
-                    needInput = false;
-                }
-
-                // decode bytes
-                result = decoder.decode(bytes, out, false);
-
-                if (result.isUnderflow()) {
-                    // compact the buffer if no space left
-                    if (bytes.limit() == bytes.capacity()) {
-                        bytes.compact();
-                        bytes.limit(bytes.position());
-                        bytes.position(0);
-                    }
-                    needInput = true;
-                } else {
-                    break;
-                }
-            }
-
-            if (result == CoderResult.UNDERFLOW && endOfInput) {
-                result = decoder.decode(bytes, out, true);
-                decoder.flush(out);
-                decoder.reset();
-            }
-            if (result.isMalformed()) {
-                throw new MalformedInputException(result.length());
-            } else if (result.isUnmappable()) {
-                throw new UnmappableCharacterException(result.length());
-            }
-
-            return out.position() - offset == 0 ? -1 : out.position() - offset;
-        }
-    }
-
-    /*
-     * Answer a boolean indicating whether or not this InputStreamReader is
-     * open.
-     */
-    private boolean isOpen() {
-        return in != null;
-    }
-
-    /**
-     * Indicates whether this reader is ready to be read without blocking. If
-     * the result is {@code true}, the next {@code read()} will not block. If
-     * the result is {@code false} then this reader may or may not block when
-     * {@code read()} is called. This implementation returns {@code true} if
-     * there are bytes available in the buffer or the source stream has bytes
-     * available.
-     *
-     * @return {@code true} if the receiver will not block when {@code read()}
-     *         is called, {@code false} if unknown or blocking will occur.
-     * @throws IOException
-     *             if this reader is closed or some other I/O error occurs.
-     */
-    @Override
-    public boolean ready() throws IOException {
-        synchronized (lock) {
-            if (in == null) {
-                throw new IOException("InputStreamReader is closed.");
-            }
-            try {
-                return bytes.hasRemaining() || in.available() > 0;
-            } catch (IOException e) {
-                return false;
-            }
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-//import java.util.logging.LogRecord;
-//import java.util.logging.Logger;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Internal logger.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.0
- */
-public final class Log
-{
-    ///CLOVER:OFF
-
-    public static enum Level
-    {
-        TRACE,
-        DEBUG,
-        INFO,
-        WARN,
-        ERROR
-    }
-
-    public static final boolean TRACE = Configuration.getBoolean(Log.class.getName() + ".trace");
-
-    public static final boolean DEBUG = TRACE || Configuration.getBoolean(Log.class.getName() + ".debug");
-
-    private static PrintStream output = System.err;
-
-    private static boolean useJul = Configuration.getBoolean("jline.log.jul");
-
-    public static PrintStream getOutput() {
-        return output;
-    }
-
-    public static void setOutput(final PrintStream out) {
-        output = checkNotNull(out);
-    }
-
-    /**
-     * Helper to support rendering messages.
-     */
-    @TestAccessible
-    static void render(final PrintStream out, final Object message) {
-        if (message.getClass().isArray()) {
-            Object[] array = (Object[]) message;
-
-            out.print("[");
-            for (int i = 0; i < array.length; i++) {
-                out.print(array[i]);
-                if (i + 1 < array.length) {
-                    out.print(",");
-                }
-            }
-            out.print("]");
-        }
-        else {
-            out.print(message);
-        }
-    }
-
-    @TestAccessible
-    static void log(final Level level, final Object... messages) {
-        if (useJul) {
-            logWithJul(level, messages);
-            return;
-        }
-        //noinspection SynchronizeOnNonFinalField
-        synchronized (output) {
-            output.format("[%s] ", level);
-
-            for (int i=0; i<messages.length; i++) {
-                // Special handling for the last message if its a throwable, render its stack on the next line
-                if (i + 1 == messages.length && messages[i] instanceof Throwable) {
-                    output.println();
-                    ((Throwable)messages[i]).printStackTrace(output);
-                }
-                else {
-                    render(output, messages[i]);
-                }
-            }
-
-            output.println();
-            output.flush();
-        }
-    }
-
-    static void logWithJul(Level level, Object... messages) {
-//        Logger logger = Logger.getLogger("jline");
-//        Throwable cause = null;
-//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-//        PrintStream ps = new PrintStream(baos);
-//        for (int i = 0; i < messages.length; i++) {
-//            // Special handling for the last message if its a throwable, render its stack on the next line
-//            if (i + 1 == messages.length && messages[i] instanceof Throwable) {
-//                cause = (Throwable) messages[i];
-//            }
-//            else {
-//                render(ps, messages[i]);
-//            }
-//        }
-//        ps.close();
-//        LogRecord r = new LogRecord(toJulLevel(level), baos.toString());
-//        r.setThrown(cause);
-//        logger.log(r);
-    }
-
-//    private static java.util.logging.Level toJulLevel(Level level) {
-//        switch (level) {
-//            case TRACE:
-//                return java.util.logging.Level.FINEST;
-//            case DEBUG:
-//                return java.util.logging.Level.FINE;
-//            case INFO:
-//                return java.util.logging.Level.INFO;
-//            case WARN:
-//                return java.util.logging.Level.WARNING;
-//            case ERROR:
-//                return java.util.logging.Level.SEVERE;
-//            default:
-//                throw new IllegalArgumentException();
-//        }
-//    }
-
-    public static void trace(final Object... messages) {
-        if (TRACE) {
-            log(Level.TRACE, messages);
-        }
-    }
-
-    public static void debug(final Object... messages) {
-        if (TRACE || DEBUG) {
-            log(Level.DEBUG, messages);
-        }
-    }
-
-    /**
-     * @since 2.7
-     */
-    public static void info(final Object... messages) {
-        log(Level.INFO, messages);
-    }
-
-    public static void warn(final Object... messages) {
-        log(Level.WARN, messages);
-    }
-
-    public static void error(final Object... messages) {
-        log(Level.ERROR, messages);
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,311 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * This class wraps a regular input stream and allows it to appear as if it
- * is non-blocking; that is, reads can be performed against it that timeout
- * if no data is seen for a period of time.  This effect is achieved by having
- * a separate thread perform all non-blocking read requests and then
- * waiting on the thread to complete.
- *
- * <p>VERY IMPORTANT NOTES
- * <ul>
- *   <li> This class is not thread safe. It expects at most one reader.
- *   <li> The {@link #shutdown()} method must be called in order to shut down
- *          the thread that handles blocking I/O.
- * </ul>
- * @since 2.7
- * @author Scott C. Gray <scottgray1@gmail.com>
- */
-public class NonBlockingInputStream
-    extends InputStream
-    implements Runnable
-{
-    private InputStream in;               // The actual input stream
-    private int    ch   = -2;             // Recently read character
-
-    private boolean     threadIsReading      = false;
-    private boolean     isShutdown           = false;
-    private IOException exception            = null;
-    private boolean     nonBlockingEnabled;
-
-    /**
-     * Creates a <code>NonBlockingInputStream</code> out of a normal blocking
-     * stream. Note that this call also spawn a separate thread to perform the
-     * blocking I/O on behalf of the thread that is using this class. The
-     * {@link #shutdown()} method must be called in order to shut this thread down.
-     * @param in The input stream to wrap
-     * @param isNonBlockingEnabled If true, then the non-blocking methods
-     *   {@link #read(long)} and {@link #peek(long)} will be available and,
-     *   more importantly, the thread will be started to provide support for the
-     *   feature.  If false, then this class acts as a clean-passthru for the
-     *   underlying I/O stream and provides very little overhead.
-     */
-    public NonBlockingInputStream (InputStream in, boolean isNonBlockingEnabled) {
-        this.in                 = in;
-        this.nonBlockingEnabled = isNonBlockingEnabled;
-
-        if (isNonBlockingEnabled) {
-            Thread t = new Thread(this);
-            t.setName("NonBlockingInputStreamThread");
-            t.setDaemon(true);
-            t.start();
-        }
-    }
-
-    /**
-     * Shuts down the thread that is handling blocking I/O. Note that if the
-     * thread is currently blocked waiting for I/O it will not actually
-     * shut down until the I/O is received.  Shutting down the I/O thread
-     * does not prevent this class from being used, but causes the
-     * non-blocking methods to fail if called and causes {@link #isNonBlockingEnabled()}
-     * to return false.
-     */
-    public synchronized void shutdown() {
-        if (!isShutdown && nonBlockingEnabled) {
-            isShutdown = true;
-            notify();
-        }
-    }
-
-    /**
-     * Non-blocking is considered enabled if the feature is enabled and the
-     * I/O thread has not been shut down.
-     * @return true if non-blocking mode is enabled.
-     */
-    public boolean isNonBlockingEnabled() {
-        return nonBlockingEnabled && !isShutdown;
-    }
-
-    @Override
-    public void close() throws IOException {
-        /*
-         * The underlying input stream is closed first. This means that if the
-         * I/O thread was blocked waiting on input, it will be woken for us.
-         */
-        in.close();
-        shutdown();
-    }
-
-    @Override
-    public int read() throws IOException {
-        if (nonBlockingEnabled)
-            return read(0L, false);
-        return in.read ();
-    }
-
-    /**
-     * Peeks to see if there is a byte waiting in the input stream without
-     * actually consuming the byte.
-     *
-     * @param timeout The amount of time to wait, 0 == forever
-     * @return -1 on eof, -2 if the timeout expired with no available input
-     *   or the character that was read (without consuming it).
-     */
-    public int peek(long timeout) throws IOException {
-        if (!nonBlockingEnabled || isShutdown) {
-            throw new UnsupportedOperationException ("peek() "
-                + "cannot be called as non-blocking operation is disabled");
-        }
-        return read(timeout, true);
-    }
-
-    /**
-     * Attempts to read a character from the input stream for a specific
-     * period of time.
-     * @param timeout The amount of time to wait for the character
-     * @return The character read, -1 if EOF is reached, or -2 if the
-     *   read timed out.
-     */
-    public int read(long timeout) throws IOException {
-        if (!nonBlockingEnabled || isShutdown) {
-            throw new UnsupportedOperationException ("read() with timeout "
-                + "cannot be called as non-blocking operation is disabled");
-        }
-        return read(timeout, false);
-    }
-
-    /**
-     * Attempts to read a character from the input stream for a specific
-     * period of time.
-     * @param timeout The amount of time to wait for the character
-     * @return The character read, -1 if EOF is reached, or -2 if the
-     *   read timed out.
-     */
-    private synchronized int read(long timeout, boolean isPeek) throws IOException {
-        /*
-         * If the thread hit an IOException, we report it.
-         */
-        if (exception != null) {
-            assert ch == -2;
-            IOException toBeThrown = exception;
-            if (!isPeek)
-                exception = null;
-            throw toBeThrown;
-        }
-
-        /*
-         * If there was a pending character from the thread, then
-         * we send it. If the timeout is 0L or the thread was shut down
-         * then do a local read.
-         */
-        if (ch >= -1) {
-            assert exception == null;
-        }
-        else if ((timeout == 0L || isShutdown) && !threadIsReading) {
-            ch = in.read();
-        }
-        else {
-            /*
-             * If the thread isn't reading already, then ask it to do so.
-             */
-            if (!threadIsReading) {
-                threadIsReading = true;
-                notify();
-            }
-
-            boolean isInfinite = timeout <= 0L;
-
-            /*
-             * So the thread is currently doing the reading for us. So
-             * now we play the waiting game.
-             */
-            while (isInfinite || timeout > 0L)  {
-                long start = System.currentTimeMillis ();
-
-                try {
-                    wait(timeout);
-                }
-                catch (InterruptedException e) {
-                    /* IGNORED */
-                }
-
-                if (exception != null) {
-                    assert ch == -2;
-
-                    IOException toBeThrown = exception;
-                    if (!isPeek)
-                        exception = null;
-                    throw toBeThrown;
-                }
-
-                if (ch >= -1) {
-                    assert exception == null;
-                    break;
-                }
-
-                if (!isInfinite) {
-                    timeout -= System.currentTimeMillis() - start;
-                }
-            }
-        }
-
-        /*
-         * ch is the character that was just read. Either we set it because
-         * a local read was performed or the read thread set it (or failed to
-         * change it).  We will return it's value, but if this was a peek
-         * operation, then we leave it in place.
-         */
-        int ret = ch;
-        if (!isPeek) {
-            ch = -2;
-        }
-        return ret;
-    }
-
-    /**
-     * This version of read() is very specific to jline's purposes, it
-     * will always always return a single byte at a time, rather than filling
-     * the entire buffer.
-     */
-    @Override
-    public int read (byte[] b, int off, int len) throws IOException {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if (off < 0 || len < 0 || len > b.length - off) {
-            throw new IndexOutOfBoundsException();
-        } else if (len == 0) {
-            return 0;
-        }
-
-        int c;
-        if (nonBlockingEnabled)
-            c = this.read(0L);
-        else
-            c = in.read();
-
-        if (c == -1) {
-            return -1;
-        }
-        b[off] = (byte)c;
-        return 1;
-    }
-
-    //@Override
-    public void run () {
-        Log.debug("NonBlockingInputStream start");
-        boolean needToShutdown = false;
-        boolean needToRead = false;
-
-        while (!needToShutdown) {
-
-            /*
-             * Synchronize to grab variables accessed by both this thread
-             * and the accessing thread.
-             */
-            synchronized (this) {
-                needToShutdown = this.isShutdown;
-                needToRead     = this.threadIsReading;
-
-                try {
-                    /*
-                     * Nothing to do? Then wait.
-                     */
-                    if (!needToShutdown && !needToRead) {
-                        wait(0);
-                    }
-                }
-                catch (InterruptedException e) {
-                    /* IGNORED */
-                }
-            }
-
-            /*
-             * We're not shutting down, but we need to read. This cannot
-             * happen while we are holding the lock (which we aren't now).
-             */
-            if (!needToShutdown && needToRead) {
-                int          charRead = -2;
-                IOException  failure = null;
-                try {
-                    charRead = in.read();
-                }
-                catch (IOException e) {
-                    failure = e;
-                }
-
-                /*
-                 * Re-grab the lock to update the state.
-                 */
-                synchronized (this) {
-                    exception       = failure;
-                    ch              = charRead;
-                    threadIsReading = false;
-                    notify();
-                }
-            }
-        }
-
-        Log.debug("NonBlockingInputStream shutdown");
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.lang.annotation.*;
-
-/**
- * Marker for reference which can be a null value.
- *
- * @since 2.7
- */
-@Documented
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
-public @interface Nullable
-{
-    String value() default "";
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-// Some bits lifted from Guava's ( http://code.google.com/p/guava-libraries/ ) Preconditions.
-
-/**
- * Preconditions.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.7
- */
-public class Preconditions
-{
-    public static <T> T checkNotNull(final T reference) {
-        if (reference == null) {
-            throw new NullPointerException();
-        }
-        return reference;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Manages the JLine shutdown-hook thread and tasks to execute on shutdown.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.7
- */
-public class ShutdownHooks
-{
-    public static final String JLINE_SHUTDOWNHOOK = "jline.shutdownhook";
-
-    private static final boolean enabled = Configuration.getBoolean(JLINE_SHUTDOWNHOOK, true);
-
-    private static final List<Task> tasks = new ArrayList<Task>();
-
-    private static Thread hook;
-
-    public static synchronized <T extends Task> T add(final T task) {
-        checkNotNull(task);
-
-        // If not enabled ignore
-        if (!enabled) {
-            Log.debug("Shutdown-hook is disabled; not installing: ", task);
-            return task;
-        }
-
-        // Install the hook thread if needed
-        if (hook == null) {
-            hook = addHook(new Thread("JLine Shutdown Hook")
-            {
-                @Override
-                public void run() {
-                    runTasks();
-                }
-            });
-        }
-
-        // Track the task
-        Log.debug("Adding shutdown-hook task: ", task);
-        tasks.add(task);
-
-        return task;
-    }
-
-    private static synchronized void runTasks() {
-        Log.debug("Running all shutdown-hook tasks");
-
-        // Iterate through copy of tasks list
-        for (Task task : tasks.toArray(new Task[tasks.size()])) {
-            Log.debug("Running task: ", task);
-            try {
-                task.run();
-            }
-            catch (Throwable e) {
-                Log.warn("Task failed", e);
-            }
-        }
-
-        tasks.clear();
-    }
-
-    private static Thread addHook(final Thread thread) {
-        Log.debug("Registering shutdown-hook: ", thread);
-        try {
-            Runtime.getRuntime().addShutdownHook(thread);
-        }
-        catch (AbstractMethodError e) {
-            // JDK 1.3+ only method. Bummer.
-            Log.debug("Failed to register shutdown-hook", e);
-        }
-        return thread;
-    }
-
-    public static synchronized void remove(final Task task) {
-        checkNotNull(task);
-
-        // ignore if not enabled or hook never installed
-        if (!enabled || hook == null) {
-            return;
-        }
-
-        // Drop the task
-        tasks.remove(task);
-
-        // If there are no more tasks, then remove the hook thread
-        if (tasks.isEmpty()) {
-            removeHook(hook);
-            hook = null;
-        }
-    }
-
-    private static void removeHook(final Thread thread) {
-        Log.debug("Removing shutdown-hook: ", thread);
-
-        try {
-            Runtime.getRuntime().removeShutdownHook(thread);
-        }
-        catch (AbstractMethodError e) {
-            // JDK 1.3+ only method. Bummer.
-            Log.debug("Failed to remove shutdown-hook", e);
-        }
-        catch (IllegalStateException e) {
-            // The VM is shutting down, not a big deal; ignore
-        }
-    }
-
-    /**
-     * Essentially a {@link Runnable} which allows running to throw an exception.
-     */
-    public static interface Task
-    {
-        void run() throws Exception;
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,360 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.text.MessageFormat;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static jdk.internal.jline.internal.Preconditions.checkNotNull;
-
-/**
- * Provides access to terminal line settings via <tt>stty</tt>.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.0
- */
-public final class TerminalLineSettings
-{
-    public static final String JLINE_STTY = "jline.stty";
-
-    public static final String DEFAULT_STTY = "stty";
-
-    public static final String JLINE_SH = "jline.sh";
-
-    public static final String DEFAULT_SH = "sh";
-
-    private static final String UNDEFINED;
-
-    public static final String DEFAULT_TTY = "/dev/tty";
-
-    private static final boolean SUPPORTS_REDIRECT;
-
-    private static final Object REDIRECT_INHERIT;
-    private static final Method REDIRECT_INPUT_METHOD;
-
-    private static final Map<String, TerminalLineSettings> SETTINGS = new HashMap<String, TerminalLineSettings>();
-
-    static {
-        if (Configuration.isHpux()) {
-            UNDEFINED = "^-";
-        } else {
-            UNDEFINED = "undef";
-        }
-
-        boolean supportsRedirect;
-        Object redirectInherit = null;
-        Method redirectInputMethod = null;
-        try {
-            Class<?> redirect = Class.forName("java.lang.ProcessBuilder$Redirect");
-            redirectInherit = redirect.getField("INHERIT").get(null);
-            redirectInputMethod = ProcessBuilder.class.getMethod("redirectInput", redirect);
-            supportsRedirect = System.class.getMethod("console").invoke(null) != null;
-        } catch (Throwable t) {
-            supportsRedirect = false;
-        }
-        SUPPORTS_REDIRECT = supportsRedirect;
-        REDIRECT_INHERIT = redirectInherit;
-        REDIRECT_INPUT_METHOD = redirectInputMethod;
-    }
-
-    private String sttyCommand;
-
-    private String shCommand;
-
-    private String ttyDevice;
-
-    private String config;
-    private String initialConfig;
-
-    private long configLastFetched;
-
-    private boolean useRedirect;
-
-    @Deprecated
-    public TerminalLineSettings() throws IOException, InterruptedException {
-        this(DEFAULT_TTY);
-    }
-
-    @Deprecated
-    public TerminalLineSettings(String ttyDevice) throws IOException, InterruptedException {
-        this(ttyDevice, false);
-    }
-
-    private TerminalLineSettings(String ttyDevice, boolean unused) throws IOException, InterruptedException {
-        checkNotNull(ttyDevice);
-        this.sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
-        this.shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
-        this.ttyDevice = ttyDevice;
-        this.useRedirect = SUPPORTS_REDIRECT && DEFAULT_TTY.equals(ttyDevice);
-        this.initialConfig = get("-g").trim();
-        this.config = get("-a");
-        this.configLastFetched = System.currentTimeMillis();
-
-        Log.debug("Config: ", config);
-
-        // sanity check
-        if (config.length() == 0) {
-            throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
-        }
-    }
-
-    public static synchronized TerminalLineSettings getSettings(String device) throws IOException, InterruptedException {
-        TerminalLineSettings settings = SETTINGS.get(device);
-        if (settings == null) {
-            settings = new TerminalLineSettings(device, false);
-            SETTINGS.put(device, settings);
-        }
-        return settings;
-    }
-
-    public String getTtyDevice() {
-        return ttyDevice;
-    }
-
-    public String getConfig() {
-        return config;
-    }
-
-    public void restore() throws IOException, InterruptedException {
-        set(initialConfig);
-    }
-
-    public String get(final String args) throws IOException, InterruptedException {
-        checkNotNull(args);
-        return stty(args);
-    }
-
-    public void set(final String args) throws IOException, InterruptedException {
-        checkNotNull(args);
-        stty(args.split(" "));
-    }
-
-    public void set(final String... args) throws IOException, InterruptedException {
-        checkNotNull(args);
-        stty(args);
-    }
-
-    public void undef(final String name) throws IOException, InterruptedException {
-        checkNotNull(name);
-        stty(name, UNDEFINED);
-    }
-
-    /**
-     * <p>
-     * Get the value of a stty property, including the management of a cache.
-     * </p>
-     *
-     * @param name the stty property.
-     * @return the stty property value.
-     */
-    public int getProperty(String name) {
-        checkNotNull(name);
-        if (!fetchConfig(name)) {
-            return -1;
-        }
-        return getProperty(name, config);
-    }
-
-    public String getPropertyAsString(String name) {
-        checkNotNull(name);
-        if (!fetchConfig(name)) {
-            return null;
-        }
-        return getPropertyAsString(name, config);
-    }
-
-    private boolean fetchConfig(String name) {
-        long currentTime = System.currentTimeMillis();
-        try {
-            // tty properties are cached so we don't have to worry too much about getting term width/height
-            if (config == null || currentTime - configLastFetched > 1000) {
-                config = get("-a");
-            }
-        } catch (Exception e) {
-            if (e instanceof InterruptedException) {
-                Thread.currentThread().interrupt();
-            }
-            Log.debug("Failed to query stty ", name, "\n", e);
-            if (config == null) {
-                return false;
-            }
-        }
-
-        // always update the last fetched time and try to parse the output
-        if (currentTime - configLastFetched > 1000) {
-            configLastFetched = currentTime;
-        }
-        return true;
-    }
-
-    /**
-     * <p>
-     * Parses a stty output (provided by stty -a) and return the value of a given property.
-     * </p>
-     *
-     * @param name property name.
-     * @param stty string resulting of stty -a execution.
-     * @return value of the given property.
-     */
-    protected static String getPropertyAsString(String name, String stty) {
-        // try the first kind of regex
-        Pattern pattern = Pattern.compile(name + "\\s+=\\s+(.*?)[;\\n\\r]");
-        Matcher matcher = pattern.matcher(stty);
-        if (!matcher.find()) {
-            // try a second kind of regex
-            pattern = Pattern.compile(name + "\\s+([^;]*)[;\\n\\r]");
-            matcher = pattern.matcher(stty);
-            if (!matcher.find()) {
-                // try a second try of regex
-                pattern = Pattern.compile("(\\S*)\\s+" + name);
-                matcher = pattern.matcher(stty);
-                if (!matcher.find()) {
-                    return null;
-                }
-            }
-        }
-        return matcher.group(1);
-    }
-
-    protected static int getProperty(String name, String stty) {
-        String str = getPropertyAsString(name, stty);
-        return str != null ? parseControlChar(str) : -1;
-    }
-
-    private static int parseControlChar(String str) {
-        // under
-        if ("<undef>".equals(str)) {
-            return -1;
-        }
-        // octal
-        if (str.charAt(0) == '0') {
-            return Integer.parseInt(str, 8);
-        }
-        // decimal
-        if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
-            return Integer.parseInt(str, 10);
-        }
-        // control char
-        if (str.charAt(0) == '^') {
-            if (str.charAt(1) == '?') {
-                return 127;
-            } else {
-                return str.charAt(1) - 64;
-            }
-        } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
-            if (str.charAt(2) == '^') {
-                if (str.charAt(3) == '?') {
-                    return 127 + 128;
-                } else {
-                    return str.charAt(3) - 64 + 128;
-                }
-            } else {
-                return str.charAt(2) + 128;
-            }
-        } else {
-            return str.charAt(0);
-        }
-    }
-
-    private String stty(final String... args) throws IOException, InterruptedException {
-        String[] s = new String[args.length + 1];
-        s[0] = sttyCommand;
-        System.arraycopy(args, 0, s, 1, args.length);
-        return exec(s);
-    }
-
-    private String exec(final String... cmd) throws IOException, InterruptedException {
-        checkNotNull(cmd);
-
-        Log.trace("Running: ", cmd);
-
-        Process p = null;
-        if (useRedirect) {
-            try {
-                p = inheritInput(new ProcessBuilder(cmd)).start();
-            } catch (Throwable t) {
-                useRedirect = false;
-            }
-        }
-        if (p == null) {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < cmd.length; i++) {
-                if (i > 0) {
-                    sb.append(' ');
-                }
-                sb.append(cmd[i]);
-            }
-            sb.append(" < ");
-            sb.append(ttyDevice);
-            p = new ProcessBuilder(shCommand, "-c", sb.toString()).start();
-        }
-
-        String result = waitAndCapture(p);
-
-        Log.trace("Result: ", result);
-
-        return result;
-    }
-
-    private static ProcessBuilder inheritInput(ProcessBuilder pb) throws Exception {
-        REDIRECT_INPUT_METHOD.invoke(pb, REDIRECT_INHERIT);
-        return pb;
-    }
-
-    public static String waitAndCapture(Process p) throws IOException, InterruptedException {
-        ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        InputStream in = null;
-        InputStream err = null;
-        OutputStream out = null;
-        try {
-            int c;
-            in = p.getInputStream();
-            while ((c = in.read()) != -1) {
-                bout.write(c);
-            }
-            err = p.getErrorStream();
-            while ((c = err.read()) != -1) {
-                bout.write(c);
-            }
-            out = p.getOutputStream();
-            p.waitFor();
-        }
-        finally {
-            close(in, out, err);
-        }
-
-        return bout.toString();
-    }
-
-    private static void close(final Closeable... closeables) {
-        for (Closeable c : closeables) {
-            if (c != null) {
-                try {
-                    c.close();
-                } catch (Exception e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-}
-
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.CONSTRUCTOR;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Marker annotation for members which are exposed for testing access.
- *
- * @since 2.7
- */
-@Retention(RUNTIME)
-@Target({TYPE, CONSTRUCTOR, METHOD, FIELD, PARAMETER})
-@Documented
-public @interface TestAccessible
-{
-    // empty
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * 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
- */
-package jdk.internal.jline.internal;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * URL helpers.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
- * @since 2.7
- */
-public class Urls
-{
-    public static URL create(final String input) {
-        if (input == null) {
-            return null;
-        }
-        try {
-            return new URL(input);
-        }
-        catch (MalformedURLException e) {
-            return create(new File(input));
-        }
-    }
-
-    public static URL create(final File file) {
-        try {
-            return file != null ? file.toURI().toURL() : null;
-        }
-        catch (MalformedURLException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-}
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * 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
- */
-/**
- * Internal support.
- *
- * @since 2.0
- */
-package jdk.internal.jline.internal;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
- * 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
- */
-/**
- * JLine 2.
- *
- * @since 2.0
- */
-package jdk.internal.jline;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/BindingReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.keymap;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import jdk.internal.org.jline.reader.EndOfFileException;
+import jdk.internal.org.jline.utils.ClosedException;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+
+/**
+ * The BindingReader will transform incoming chars into
+ * key bindings
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class BindingReader {
+
+    protected final NonBlockingReader reader;
+    protected final StringBuilder opBuffer = new StringBuilder();
+    protected final Deque<Integer> pushBackChar = new ArrayDeque<>();
+    protected String lastBinding;
+
+    public BindingReader(NonBlockingReader reader) {
+        this.reader = reader;
+    }
+
+    /**
+     * Read from the input stream and decode an operation from the key map.
+     *
+     * The input stream will be read character by character until a matching
+     * binding can be found.  Characters that can't possibly be matched to
+     * any binding will be send with the {@link KeyMap#getNomatch()} binding.
+     * Unicode (&gt;= 128) characters will be matched to {@link KeyMap#getUnicode()}.
+     * If the current key sequence is ambiguous, i.e. the sequence is bound but
+     * it's also a prefix to other sequences, then the {@link KeyMap#getAmbiguousTimeout()}
+     * timeout will be used to wait for another incoming character.
+     * If a character comes, the disambiguation will be done.  If the timeout elapses
+     * and no character came in, or if the timeout is &lt;= 0, the current bound operation
+     * will be returned.
+     *
+     * @param keys the KeyMap to use for decoding the input stream
+     * @param <T> the type of bindings to be read
+     * @return the decoded binding or <code>null</code> if the end of
+     *         stream has been reached
+     */
+    public <T> T readBinding(KeyMap<T> keys) {
+        return readBinding(keys, null, true);
+    }
+
+    public <T> T readBinding(KeyMap<T> keys, KeyMap<T> local) {
+        return readBinding(keys, local, true);
+    }
+
+    public <T> T readBinding(KeyMap<T> keys, KeyMap<T> local, boolean block) {
+        lastBinding = null;
+        T o = null;
+        int[] remaining = new int[1];
+        boolean hasRead = false;
+        for (;;) {
+            if (local != null) {
+                o = local.getBound(opBuffer, remaining);
+            }
+            if (o == null && (local == null || remaining[0] >= 0)) {
+                o = keys.getBound(opBuffer, remaining);
+            }
+            // We have a binding and additional chars
+            if (o != null) {
+                if (remaining[0] >= 0) {
+                    runMacro(opBuffer.substring(opBuffer.length() - remaining[0]));
+                    opBuffer.setLength(opBuffer.length() - remaining[0]);
+                }
+                else {
+                    long ambiguousTimeout = keys.getAmbiguousTimeout();
+                    if (ambiguousTimeout > 0 && peekCharacter(ambiguousTimeout) != NonBlockingReader.READ_EXPIRED) {
+                        o = null;
+                    }
+                }
+                if (o != null) {
+                    lastBinding = opBuffer.toString();
+                    opBuffer.setLength(0);
+                    return o;
+                }
+                // We don't match anything
+            } else if (remaining[0] > 0) {
+                int cp = opBuffer.codePointAt(0);
+                String rem = opBuffer.substring(Character.charCount(cp));
+                lastBinding = opBuffer.substring(0, Character.charCount(cp));
+                // Unicode character
+                o = (cp >= KeyMap.KEYMAP_LENGTH) ? keys.getUnicode() : keys.getNomatch();
+                opBuffer.setLength(0);
+                opBuffer.append(rem);
+                if (o != null) {
+                    return o;
+                }
+            }
+
+            if (!block && hasRead) {
+                break;
+            }
+            int c = readCharacter();
+            if (c == -1) {
+                return null;
+            }
+            opBuffer.appendCodePoint(c);
+            hasRead = true;
+        }
+        return null;
+    }
+
+    /**
+     * Read a codepoint from the terminal.
+     *
+     * @return the character, or -1 if an EOF is received.
+     */
+    public int readCharacter() {
+        if (!pushBackChar.isEmpty()) {
+            return pushBackChar.pop();
+        }
+        try {
+            int c = NonBlockingReader.READ_EXPIRED;
+            int s = 0;
+            while (c == NonBlockingReader.READ_EXPIRED) {
+                c = reader.read(100L);
+                if (c >= 0 && Character.isHighSurrogate((char) c)) {
+                    s = c;
+                    c = NonBlockingReader.READ_EXPIRED;
+                }
+            }
+            return s != 0 ? Character.toCodePoint((char) s, (char) c) : c;
+        } catch (ClosedException e) {
+            throw new EndOfFileException(e);
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public int peekCharacter(long timeout) {
+        if (!pushBackChar.isEmpty()) {
+            return pushBackChar.peek();
+        }
+        try {
+            return reader.peek(timeout);
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public void runMacro(String macro) {
+        macro.codePoints().forEachOrdered(pushBackChar::addLast);
+    }
+
+    public String getCurrentBuffer() {
+        return opBuffer.toString();
+    }
+
+    public String getLastBinding() {
+        return lastBinding;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/keymap/KeyMap.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,460 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.keymap;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.Curses;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+
+/**
+ * The KeyMap class contains all bindings from keys to operations.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.6
+ */
+public class KeyMap<T> {
+
+    public static final int KEYMAP_LENGTH = 128;
+    public static final long DEFAULT_AMBIGUOUS_TIMEOUT = 1000L;
+
+    private Object[] mapping = new Object[KEYMAP_LENGTH];
+    private T anotherKey = null;
+    private T unicode;
+    private T nomatch;
+    private long ambiguousTimeout = DEFAULT_AMBIGUOUS_TIMEOUT;
+
+    public static String display(String key) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("\"");
+        for (int i = 0; i < key.length(); i++) {
+            char c = key.charAt(i);
+            if (c < 32) {
+                sb.append('^');
+                sb.append((char) (c + 'A' - 1));
+            } else if (c == 127) {
+                sb.append("^?");
+            } else if (c == '^' || c == '\\') {
+                sb.append('\\').append(c);
+            } else if (c >= 128) {
+                sb.append(String.format("\\u%04x", (int) c));
+            } else {
+                sb.append(c);
+            }
+        }
+        sb.append("\"");
+        return sb.toString();
+    }
+
+    public static String translate(String str) {
+        int i;
+        if (!str.isEmpty()) {
+            char c = str.charAt(0);
+            if ((c == '\'' || c == '"') && str.charAt(str.length() - 1) == c) {
+                str = str.substring(1, str.length() - 1);
+            }
+        }
+        StringBuilder keySeq = new StringBuilder();
+        for (i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (c == '\\') {
+                if (++i >= str.length()) {
+                    break;
+                }
+                c = str.charAt(i);
+                switch (c) {
+                    case 'a':
+                        c = 0x07;
+                        break;
+                    case 'b':
+                        c = '\b';
+                        break;
+                    case 'd':
+                        c = 0x7f;
+                        break;
+                    case 'e':
+                    case 'E':
+                        c = 0x1b;
+                        break;
+                    case 'f':
+                        c = '\f';
+                        break;
+                    case 'n':
+                        c = '\n';
+                        break;
+                    case 'r':
+                        c = '\r';
+                        break;
+                    case 't':
+                        c = '\t';
+                        break;
+                    case 'v':
+                        c = 0x0b;
+                        break;
+                    case '\\':
+                        c = '\\';
+                        break;
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                        c = 0;
+                        for (int j = 0; j < 3; j++, i++) {
+                            if (i >= str.length()) {
+                                break;
+                            }
+                            int k = Character.digit(str.charAt(i), 8);
+                            if (k < 0) {
+                                break;
+                            }
+                            c = (char) (c * 8 + k);
+                        }
+                        i--;
+                        c &= 0xFF;
+                        break;
+                    case 'x':
+                        i++;
+                        c = 0;
+                        for (int j = 0; j < 2; j++, i++) {
+                            if (i >= str.length()) {
+                                break;
+                            }
+                            int k = Character.digit(str.charAt(i), 16);
+                            if (k < 0) {
+                                break;
+                            }
+                            c = (char) (c * 16 + k);
+                        }
+                        i--;
+                        c &= 0xFF;
+                        break;
+                    case 'u':
+                        i++;
+                        c = 0;
+                        for (int j = 0; j < 4; j++, i++) {
+                            if (i >= str.length()) {
+                                break;
+                            }
+                            int k = Character.digit(str.charAt(i), 16);
+                            if (k < 0) {
+                                break;
+                            }
+                            c = (char) (c * 16 + k);
+                        }
+                        break;
+                    case 'C':
+                        if (++i >= str.length()) {
+                            break;
+                        }
+                        c = str.charAt(i);
+                        if (c == '-') {
+                            if (++i >= str.length()) {
+                                break;
+                            }
+                            c = str.charAt(i);
+                        }
+                        c = c == '?' ? 0x7f : (char) (Character.toUpperCase(c) & 0x1f);
+                        break;
+                }
+            } else if (c == '^') {
+                if (++i >= str.length()) {
+                    break;
+                }
+                c = str.charAt(i);
+                if (c != '^') {
+                    c = c == '?' ? 0x7f : (char) (Character.toUpperCase(c) & 0x1f);
+                }
+            }
+            keySeq.append(c);
+        }
+        return keySeq.toString();
+    }
+
+    public static Collection<String> range(String range) {
+        String[] keys = range.split("-");
+        if (keys.length != 2) {
+            return null;
+        }
+        keys[0] = translate(keys[0]);
+        keys[1] = translate(keys[1]);
+        if (keys[0].length() != keys[1].length()) {
+            return null;
+        }
+        String pfx;
+        if (keys[0].length() > 1) {
+            pfx = keys[0].substring(0, keys[0].length() - 1);
+            if (!keys[1].startsWith(pfx)) {
+                return null;
+            }
+        } else {
+            pfx = "";
+        }
+        char c0 = keys[0].charAt(keys[0].length() - 1);
+        char c1 = keys[1].charAt(keys[1].length() - 1);
+        if (c0 > c1) {
+            return null;
+        }
+        Collection<String> seqs = new ArrayList<>();
+        for (char c = c0; c <= c1; c++) {
+            seqs.add(pfx + c);
+        }
+        return seqs;
+    }
+
+
+    public static String esc() {
+        return "\033";
+    }
+
+    public static String alt(char c) {
+        return "\033" + c;
+    }
+
+    public static String alt(String c) {
+        return "\033" + c;
+    }
+
+    public static String del() {
+        return "\177";
+    }
+
+    public static String ctrl(char key) {
+        return key == '?' ? del() : Character.toString((char) (Character.toUpperCase(key) & 0x1f));
+    }
+
+    public static String key(Terminal terminal, Capability capability) {
+        return Curses.tputs(terminal.getStringCapability(capability));
+    }
+
+    public static final Comparator<String> KEYSEQ_COMPARATOR = (s1, s2) -> {
+        int len1 = s1.length();
+        int len2 = s2.length();
+        int lim = Math.min(len1, len2);
+        int k = 0;
+        while (k < lim) {
+            char c1 = s1.charAt(k);
+            char c2 = s2.charAt(k);
+            if (c1 != c2) {
+                int l = len1 - len2;
+                return l != 0 ? l : c1 - c2;
+            }
+            k++;
+        }
+        return len1 - len2;
+    };
+
+    //
+    // Methods
+    //
+
+
+    public T getUnicode() {
+        return unicode;
+    }
+
+    public void setUnicode(T unicode) {
+        this.unicode = unicode;
+    }
+
+    public T getNomatch() {
+        return nomatch;
+    }
+
+    public void setNomatch(T nomatch) {
+        this.nomatch = nomatch;
+    }
+
+    public long getAmbiguousTimeout() {
+        return ambiguousTimeout;
+    }
+
+    public void setAmbiguousTimeout(long ambiguousTimeout) {
+        this.ambiguousTimeout = ambiguousTimeout;
+    }
+
+    public T getAnotherKey() {
+        return anotherKey;
+    }
+
+    public Map<String, T> getBoundKeys() {
+        Map<String, T> bound = new TreeMap<>(KEYSEQ_COMPARATOR);
+        doGetBoundKeys(this, "", bound);
+        return bound;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> void doGetBoundKeys(KeyMap<T> keyMap, String prefix, Map<String, T> bound) {
+        if (keyMap.anotherKey != null) {
+            bound.put(prefix, keyMap.anotherKey);
+        }
+        for (int c = 0; c < keyMap.mapping.length; c++) {
+            if (keyMap.mapping[c] instanceof KeyMap) {
+                doGetBoundKeys((KeyMap<T>) keyMap.mapping[c],
+                        prefix + (char) (c),
+                        bound);
+            } else if (keyMap.mapping[c] != null) {
+                bound.put(prefix + (char) (c), (T) keyMap.mapping[c]);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public T getBound(CharSequence keySeq, int[] remaining) {
+        remaining[0] = -1;
+        if (keySeq != null && keySeq.length() > 0) {
+            char c = keySeq.charAt(0);
+            if (c >= mapping.length) {
+                remaining[0] = Character.codePointCount(keySeq, 0, keySeq.length());
+                return null;
+            } else {
+                if (mapping[c] instanceof KeyMap) {
+                    CharSequence sub = keySeq.subSequence(1, keySeq.length());
+                    return ((KeyMap<T>) mapping[c]).getBound(sub, remaining);
+                } else if (mapping[c] != null) {
+                    remaining[0] = keySeq.length() - 1;
+                    return (T) mapping[c];
+                } else {
+                    remaining[0] = keySeq.length();
+                    return anotherKey;
+                }
+            }
+        } else {
+            return anotherKey;
+        }
+    }
+
+    public T getBound(CharSequence keySeq) {
+        int[] remaining = new int[1];
+        T res = getBound(keySeq, remaining);
+        return remaining[0] <= 0 ? res : null;
+    }
+
+    public void bindIfNotBound(T function, CharSequence keySeq) {
+        if (function != null && keySeq != null) {
+            bind(this, keySeq, function, true);
+        }
+    }
+
+    public void bind(T function, CharSequence... keySeqs) {
+        for (CharSequence keySeq : keySeqs) {
+            bind(function, keySeq);
+        }
+    }
+
+    public void bind(T function, Iterable<? extends CharSequence> keySeqs) {
+        for (CharSequence keySeq : keySeqs) {
+            bind(function, keySeq);
+        }
+    }
+
+    public void bind(T function, CharSequence keySeq) {
+        if (keySeq != null) {
+            if (function == null) {
+                unbind(keySeq);
+            } else {
+                bind(this, keySeq, function, false);
+            }
+        }
+    }
+
+    public void unbind(CharSequence... keySeqs) {
+        for (CharSequence keySeq : keySeqs) {
+            unbind(keySeq);
+        }
+    }
+
+    public void unbind(CharSequence keySeq) {
+        if (keySeq != null) {
+            unbind(this, keySeq);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T unbind(KeyMap<T> map, CharSequence keySeq) {
+        KeyMap<T> prev = null;
+        if (keySeq != null && keySeq.length() > 0) {
+            for (int i = 0; i < keySeq.length() - 1; i++) {
+                char c = keySeq.charAt(i);
+                if (c > map.mapping.length) {
+                    return null;
+                }
+                if (!(map.mapping[c] instanceof KeyMap)) {
+                    return null;
+                }
+                prev = map;
+                map = (KeyMap<T>) map.mapping[c];
+            }
+            char c = keySeq.charAt(keySeq.length() - 1);
+            if (c > map.mapping.length) {
+                return null;
+            }
+            if (map.mapping[c] instanceof KeyMap) {
+                KeyMap<?> sub = (KeyMap) map.mapping[c];
+                Object res = sub.anotherKey;
+                sub.anotherKey = null;
+                return (T) res;
+            } else {
+                Object res = map.mapping[c];
+                map.mapping[c] = null;
+                int nb = 0;
+                for (int i = 0; i < map.mapping.length; i++) {
+                    if (map.mapping[i] != null) {
+                        nb++;
+                    }
+                }
+                if (nb == 0 && prev != null) {
+                    prev.mapping[keySeq.charAt(keySeq.length() - 2)] = map.anotherKey;
+                }
+                return (T) res;
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> void bind(KeyMap<T> map, CharSequence keySeq, T function, boolean onlyIfNotBound) {
+        if (keySeq != null && keySeq.length() > 0) {
+            for (int i = 0; i < keySeq.length(); i++) {
+                char c = keySeq.charAt(i);
+                if (c >= map.mapping.length) {
+                    return;
+                }
+                if (i < keySeq.length() - 1) {
+                    if (!(map.mapping[c] instanceof KeyMap)) {
+                        KeyMap<T> m = new KeyMap<>();
+                        m.anotherKey = (T) map.mapping[c];
+                        map.mapping[c] = m;
+                    }
+                    map = (KeyMap) map.mapping[c];
+                } else {
+                    if (map.mapping[c] instanceof KeyMap) {
+                        ((KeyMap) map.mapping[c]).anotherKey = function;
+                    } else {
+                        Object op = map.mapping[c];
+                        if (!onlyIfNotBound || op == null) {
+                            map.mapping[c] = function;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Binding.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,22 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * Marker interface for objects bound to key sequences.
+ *
+ * @see Macro
+ * @see Reference
+ * @see Widget
+ * @see org.jline.keymap.KeyMap
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public interface Binding {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Buffer.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.reader;
+
+public interface Buffer {
+
+    /*
+     * Read access
+     */
+
+    int cursor();
+
+    int atChar(int i);
+
+    int length();
+
+    int currChar();
+
+    int prevChar();
+
+    int nextChar();
+
+    /*
+     * Movement
+     */
+
+    boolean cursor(int position);
+
+    int move(int num);
+
+    boolean up();
+
+    boolean down();
+
+    boolean moveXY(int dx, int dy);
+
+    /*
+     * Modification
+     */
+
+    boolean clear();
+
+    boolean currChar(int c);
+
+    void write(int c);
+
+    void write(int c, boolean overTyping);
+
+    void write(CharSequence str);
+
+    void write(CharSequence str, boolean overTyping);
+
+    boolean backspace();
+
+    int backspace(int num);
+
+    boolean delete();
+
+    int delete(int num);
+
+    /*
+     * String
+     */
+
+    String substring(int start);
+
+    String substring(int start, int end);
+
+    String upToCursor();
+
+    String toString();
+
+    /*
+     * Copy
+     */
+
+    Buffer copy();
+
+    void copyFrom(Buffer buffer);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.util.Objects;
+
+/**
+ * A completion candidate.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class Candidate implements Comparable<Candidate> {
+
+    private final String value;
+    private final String displ;
+    private final String group;
+    private final String descr;
+    private final String suffix;
+    private final String key;
+    private final boolean complete;
+
+    /**
+     * Simple constructor with only a single String as an argument.
+     *
+     * @param value the candidate
+     */
+    public Candidate(String value) {
+        this(value, value, null, null, null, null, true);
+    }
+
+    /**
+     * Constructs a new Candidate.
+     *
+     * @param value the value
+     * @param displ the display string
+     * @param group the group
+     * @param descr the description
+     * @param suffix the suffix
+     * @param key the key
+     * @param complete the complete flag
+     */
+    public Candidate(String value, String displ, String group, String descr, String suffix, String key, boolean complete) {
+        Objects.requireNonNull(value);
+        this.value = value;
+        this.displ = displ;
+        this.group = group;
+        this.descr = descr;
+        this.suffix = suffix;
+        this.key = key;
+        this.complete = complete;
+    }
+
+    /**
+     * The value that will be used for the actual completion.
+     * This string should not contain ANSI sequences.
+     * @return the value
+     */
+    public String value() {
+        return value;
+    }
+
+    /**
+     * The string that will be displayed to the user.
+     * This string may contain ANSI sequences.
+     * @return the display string
+     */
+    public String displ() {
+        return displ;
+    }
+
+    /**
+     * The group name for this candidate.
+     * Candidates can be grouped together and this string is used
+     * as a key for the group and displayed to the user.
+     * @return the group
+     *
+     * @see LineReader.Option#GROUP
+     * @see LineReader.Option#AUTO_GROUP
+     */
+    public String group() {
+        return group;
+    }
+
+    /**
+     * Description of this candidate, usually a small help message
+     * to understand the meaning of this candidate.
+     * This string may contain ANSI sequences.
+     * @return the description
+     */
+    public String descr() {
+        return descr;
+    }
+
+    /**
+     * The suffix is added when this candidate is displayed.
+     * However, if the next character entered does not match,
+     * the suffix will be automatically removed.
+     * This string should not contain ANSI sequences.
+     * @return the suffix
+     *
+     * @see LineReader.Option#AUTO_REMOVE_SLASH
+     * @see LineReader#REMOVE_SUFFIX_CHARS
+     */
+    public String suffix() {
+        return suffix;
+    }
+
+    /**
+     * Candidates which have the same key will be merged together.
+     * For example, if a command has multiple aliases, they can be merged
+     * if they are using the same key.
+     * @return the key
+     */
+    public String key() {
+        return key;
+    }
+
+    /**
+     * Boolean indicating whether this candidate is complete or
+     * if the completer may further expand the candidate value
+     * after this candidate has been selected.
+     * This can be the case when completing folders for example.
+     * If the candidate is complete and is selected, a space
+     * separator will be added.
+     * @return the completion flag
+     */
+    public boolean complete() {
+        return complete;
+    }
+
+    @Override
+    public int compareTo(Candidate o) {
+        return value.compareTo(o.value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Completer.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.util.List;
+
+/**
+ * A completer is the mechanism by which tab-completion candidates will be resolved.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.3
+ */
+public interface Completer
+{
+    /**
+     * Populates <i>candidates</i> with a list of possible completions for the <i>command line</i>.
+     *
+     * The list of candidates will be sorted and filtered by the LineReader, so that
+     * the list of candidates displayed to the user will usually be smaller than
+     * the list given by the completer.  Thus it is not necessary for the completer
+     * to do any matching based on the current buffer.  On the contrary, in order
+     * for the typo matcher to work, all possible candidates for the word being
+     * completed should be returned.
+     *
+     * @param reader        The line reader
+     * @param line          The parsed command line
+     * @param candidates    The {@link List} of candidates to populate
+     */
+    void complete(LineReader reader, ParsedLine line, List<Candidate> candidates);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletingParsedLine.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * An extension of {@link ParsedLine} that, being aware of the quoting and escaping rules
+ * of the {@link org.jline.reader.Parser} that produced it, knows if and how a completion candidate
+ * should be escaped/quoted.
+ *
+ * @author Eric Bottard
+ */
+public interface CompletingParsedLine extends ParsedLine {
+
+    CharSequence escape(CharSequence candidate, boolean complete);
+
+    int rawWordCursor();
+
+    int rawWordLength();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EOFError.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package jdk.internal.org.jline.reader;
+
+public class EOFError extends SyntaxError {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String missing;
+
+    public EOFError(int line, int column, String message) {
+        this(line, column, message, null);
+    }
+
+    public EOFError(int line, int column, String message, String missing) {
+        super(line, column, message);
+        this.missing = missing;
+    }
+
+    public String getMissing() {
+        return missing;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * This exception is thrown by {@link LineReader#readLine} when
+ * user the user types ctrl-D).
+ */
+public class EndOfFileException extends RuntimeException {
+
+    private static final long serialVersionUID = 528485360925144689L;
+
+    public EndOfFileException() {
+    }
+
+    public EndOfFileException(String message) {
+        super(message);
+    }
+
+    public EndOfFileException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public EndOfFileException(Throwable cause) {
+        super(cause);
+    }
+
+    public EndOfFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Expander.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,17 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+public interface Expander {
+
+    String expandHistory(History history, String line);
+
+    String expandVar(String word);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Highlighter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,16 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+import jdk.internal.org.jline.utils.AttributedString;
+
+public interface Highlighter {
+
+    AttributedString highlight(LineReader reader, String buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/History.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Console history.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface History extends Iterable<History.Entry>
+{
+
+    /**
+     * Initialize the history for the given reader.
+     * @param reader the reader to attach to
+     */
+    void attach(LineReader reader);
+
+    /**
+     * Load history.
+     * @throws IOException if a problem occurs
+     */
+    void load() throws IOException;
+
+    /**
+     * Save history.
+     * @throws IOException if a problem occurs
+     */
+    void save() throws IOException;
+
+    /**
+     * Purge history.
+     * @throws IOException if a problem occurs
+     */
+    void purge() throws IOException;
+
+
+    int size();
+
+    default boolean isEmpty() {
+        return size() == 0;
+    }
+
+    int index();
+
+    int first();
+
+    int last();
+
+    String get(int index);
+
+    default void add(String line) {
+        add(Instant.now(), line);
+    }
+
+    void add(Instant time, String line);
+
+    /**
+     * Check if an entry should be persisted or not.
+     *
+     * @param entry the entry to check
+     * @return <code>true</code> if the given entry should be persisted, <code>false</code> otherwise
+     */
+    default boolean isPersistable(Entry entry) {
+        return true;
+    }
+
+    //
+    // Entries
+    //
+
+    interface Entry
+    {
+        int index();
+
+        Instant time();
+
+        String line();
+    }
+
+    ListIterator<Entry> iterator(int index);
+
+    default ListIterator<Entry> iterator() {
+        return iterator(first());
+    }
+
+    default Iterator<Entry> reverseIterator() {
+        return reverseIterator(last());
+    }
+
+    default Iterator<Entry> reverseIterator(int index) {
+        return new Iterator<Entry>() {
+            private final ListIterator<Entry> it = iterator(index + 1);
+            @Override
+            public boolean hasNext() {
+                return it.hasPrevious();
+            }
+            @Override
+            public Entry next() {
+                return it.previous();
+            }
+        };
+    }
+
+    //
+    // Navigation
+    //
+
+    /**
+     * Return the content of the current buffer.
+     *
+     * @return the content of the current buffer
+     */
+    String current();
+
+    /**
+     * Move the pointer to the previous element in the buffer.
+     *
+     * @return true if we successfully went to the previous element
+     */
+    boolean previous();
+
+    /**
+     * Move the pointer to the next element in the buffer.
+     *
+     * @return true if we successfully went to the next element
+     */
+    boolean next();
+
+    /**
+     * Moves the history index to the first entry.
+     *
+     * @return Return false if there are no iterator in the history or if the
+     * history is already at the beginning.
+     */
+    boolean moveToFirst();
+
+    /**
+     * This moves the history to the last entry. This entry is one position
+     * before the moveToEnd() position.
+     *
+     * @return Returns false if there were no history iterator or the history
+     * index was already at the last entry.
+     */
+    boolean moveToLast();
+
+    /**
+     * Move to the specified index in the history
+     *
+     * @param index The index to move to.
+     * @return      Returns true if the index was moved.
+     */
+    boolean moveTo(int index);
+
+    /**
+     * Move to the end of the history buffer. This will be a blank entry, after
+     * all of the other iterator.
+     */
+    void moveToEnd();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,655 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.function.IntConsumer;
+
+import jdk.internal.org.jline.keymap.KeyMap;
+import jdk.internal.org.jline.terminal.MouseEvent;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.AttributedString;
+
+/** Read lines from the console, with input editing.
+ *
+ * <h3>Thread safety</h3>
+ * The <code>LineReader</code> implementations are not thread safe,
+ * thus you should not attempt to use a single reader in several threads.
+ * Any attempt to call one of the <code>readLine</code> call while one is
+ * already executing in a different thread will immediately result in an
+ * <code>IllegalStateException</code> being thrown.  Other calls may lead to
+ * unknown behaviors. There is one exception though: users are allowed to call
+ * {@link #printAbove(String)} or {@link #printAbove(AttributedString)} at
+ * any time to allow text to be printed above the current prompt.
+ *
+ * <h3>Prompt strings</h3>
+ * It is traditional for an interactive console-based program
+ * to print a short prompt string to signal that the user is expected
+ * to type a command.  JLine supports 3 kinds of prompt string:
+ * <ul>
+ * <li> The normal prompt at the start (left) of the initial line of a command.
+ * <li> An optional right prompt at the right border of the initial line.
+ * <li> A start (left) prompt for continuation lines.  I.e. the lines
+ * after the first line of a multi-line command.
+ * </ul>
+ * <p>
+ * All of these are specified with prompt templates,
+ * which are similar to {@code printf} format strings,
+ * using the character {@code '%'} to indicate special functionality.
+ * </p>
+ * The pattern may include ANSI escapes.
+ * It may include these template markers:
+ * <dl>
+ * <dt>{@code %N}</dt>
+ * <dd>A line number. This is the sum of {@code getLineNumber()}
+ *   and a counter starting with 1 for the first continuation line.
+ * </dd>
+ * <dt>{@code %M}</dt>
+ * <dd>A short word explaining what is "missing". This is supplied from
+ * the {@link EOFError#getMissing()} method, if provided.
+ * Defaults to an empty string.
+ * </dd>
+ * <dt>{@code %}<var>n</var>{@code P}<var>c</var></dt>
+ * <dd>Insert padding at this possion, repeating the following
+ *   character <var>c</var> as needed to bring the total prompt
+ *   column width as specified by the digits <var>n</var>.
+ * </dd>
+ * <dt>{@code %P}<var>c</var></dt>
+ * <dd>As before, but use width from the initial prompt.
+ * </dd>
+ * <dt>{@code %%}</dt>
+ * <dd>A literal {@code '%'}.
+ * </dd>
+ * <dt><code>%{</code></dt><dt><code>%}</code></dt>
+ * <dd>Text between a <code>%{</code>...<code>%}</code> pair is printed as
+ * part of a prompt, but not interpreted by JLine
+ * (except that {@code '%'}-escapes are processed).  The text is assumed
+ * to take zero columns (not move the cursor).  If it changes the style,
+ * you're responsible for changing it back.  Standard ANSI escape sequences
+ * do not need to be within a <code>%{</code>...<code>%}</code> pair
+ * (though can be) since JLine knows how to deal with them.  However,
+ * these delimiters are needed for unusual non-standard escape sequences.
+ * </dd>
+ * </dl>
+ */
+
+public interface LineReader {
+
+    /**
+     * System property that can be set to avoid a warning being logged
+     * when using a Parser which does not return {@link CompletingParsedLine} objects.
+     */
+    String PROP_SUPPORT_PARSEDLINE = "org.jline.reader.support.parsedline";
+
+    //
+    // Widget names
+    //
+    String CALLBACK_INIT = "callback-init";
+    String CALLBACK_FINISH = "callback-finish";
+    String CALLBACK_KEYMAP = "callback-keymap";
+
+    String ACCEPT_LINE = "accept-line";
+    String ARGUMENT_BASE = "argument-base";
+    String BACKWARD_CHAR = "backward-char";
+    String BACKWARD_DELETE_CHAR = "backward-delete-char";
+    String BACKWARD_DELETE_WORD = "backward-delete-word";
+    String BACKWARD_KILL_LINE = "backward-kill-line";
+    String BACKWARD_KILL_WORD = "backward-kill-word";
+    String BACKWARD_WORD = "backward-word";
+    String BEEP = "beep";
+    String BEGINNING_OF_BUFFER_OR_HISTORY = "beginning-of-buffer-or-history";
+    String BEGINNING_OF_HISTORY = "beginning-of-history";
+    String BEGINNING_OF_LINE = "beginning-of-line";
+    String BEGINNING_OF_LINE_HIST = "beginning-of-line-hist";
+    String CAPITALIZE_WORD = "capitalize-word";
+    String CHARACTER_SEARCH = "character-search";
+    String CHARACTER_SEARCH_BACKWARD = "character-search-backward";
+    String CLEAR = "clear";
+    String CLEAR_SCREEN = "clear-screen";
+    String COMPLETE_PREFIX = "complete-prefix";
+    String COMPLETE_WORD = "complete-word";
+    String COPY_PREV_WORD = "copy-prev-word";
+    String COPY_REGION_AS_KILL = "copy-region-as-kill";
+    String DELETE_CHAR = "delete-char";
+    String DELETE_CHAR_OR_LIST = "delete-char-or-list";
+    String DELETE_WORD = "delete-word";
+    String DIGIT_ARGUMENT = "digit-argument";
+    String DO_LOWERCASE_VERSION = "do-lowercase-version";
+    String DOWN_CASE_WORD = "down-case-word";
+    String DOWN_HISTORY = "down-history";
+    String DOWN_LINE = "down-line";
+    String DOWN_LINE_OR_HISTORY = "down-line-or-history";
+    String DOWN_LINE_OR_SEARCH = "down-line-or-search";
+    String EMACS_BACKWARD_WORD = "emacs-backward-word";
+    String EMACS_EDITING_MODE = "emacs-editing-mode";
+    String EMACS_FORWARD_WORD = "emacs-forward-word";
+    String END_OF_BUFFER_OR_HISTORY = "end-of-buffer-or-history";
+    String END_OF_HISTORY = "end-of-history";
+    String END_OF_LINE = "end-of-line";
+    String END_OF_LINE_HIST = "end-of-line-hist";
+    String EXCHANGE_POINT_AND_MARK = "exchange-point-and-mark";
+    String EXECUTE_NAMED_CMD = "execute-named-cmd";
+    String EXPAND_HISTORY = "expand-history";
+    String EXPAND_OR_COMPLETE = "expand-or-complete";
+    String EXPAND_OR_COMPLETE_PREFIX = "expand-or-complete-prefix";
+    String EXPAND_WORD = "expand-word";
+    String FRESH_LINE = "fresh-line";
+    String FORWARD_CHAR = "forward-char";
+    String FORWARD_WORD = "forward-word";
+    String HISTORY_BEGINNING_SEARCH_BACKWARD = "history-beginning-search-backward";
+    String HISTORY_BEGINNING_SEARCH_FORWARD = "history-beginning-search-forward";
+    String HISTORY_INCREMENTAL_PATTERN_SEARCH_BACKWARD = "history-incremental-pattern-search-backward";
+    String HISTORY_INCREMENTAL_PATTERN_SEARCH_FORWARD = "history-incremental-pattern-search-forward";
+    String HISTORY_INCREMENTAL_SEARCH_BACKWARD = "history-incremental-search-backward";
+    String HISTORY_INCREMENTAL_SEARCH_FORWARD = "history-incremental-search-forward";
+    String HISTORY_SEARCH_BACKWARD = "history-search-backward";
+    String HISTORY_SEARCH_FORWARD = "history-search-forward";
+    String INSERT_CLOSE_CURLY = "insert-close-curly";
+    String INSERT_CLOSE_PAREN = "insert-close-paren";
+    String INSERT_CLOSE_SQUARE = "insert-close-square";
+    String INFER_NEXT_HISTORY = "infer-next-history";
+    String INSERT_COMMENT = "insert-comment";
+    String INSERT_LAST_WORD = "insert-last-word";
+    String KILL_BUFFER = "kill-buffer";
+    String KILL_LINE = "kill-line";
+    String KILL_REGION = "kill-region";
+    String KILL_WHOLE_LINE = "kill-whole-line";
+    String KILL_WORD = "kill-word";
+    String LIST_CHOICES = "list-choices";
+    String LIST_EXPAND = "list-expand";
+    String MAGIC_SPACE = "magic-space";
+    String MENU_EXPAND_OR_COMPLETE = "menu-expand-or-complete";
+    String MENU_COMPLETE = "menu-complete";
+    String MENU_SELECT = "menu-select";
+    String NEG_ARGUMENT = "neg-argument";
+    String OVERWRITE_MODE = "overwrite-mode";
+    String PUT_REPLACE_SELECTION = "put-replace-selection";
+    String QUOTED_INSERT = "quoted-insert";
+    String READ_COMMAND = "read-command";
+    String RECURSIVE_EDIT = "recursive-edit";
+    String REDISPLAY = "redisplay";
+    String REDRAW_LINE = "redraw-line";
+    String REDO = "redo";
+    String REVERSE_MENU_COMPLETE = "reverse-menu-complete";
+    String SELF_INSERT = "self-insert";
+    String SELF_INSERT_UNMETA = "self-insert-unmeta";
+    String SEND_BREAK = "abort";
+    String SET_LOCAL_HISTORY = "set-local-history";
+    String SET_MARK_COMMAND = "set-mark-command";
+    String SPELL_WORD = "spell-word";
+    String SPLIT_UNDO = "split-undo";
+    String TRANSPOSE_CHARS = "transpose-chars";
+    String TRANSPOSE_WORDS = "transpose-words";
+    String UNDEFINED_KEY = "undefined-key";
+    String UNDO = "undo";
+    String UNIVERSAL_ARGUMENT = "universal-argument";
+    String UP_CASE_WORD = "up-case-word";
+    String UP_HISTORY = "up-history";
+    String UP_LINE = "up-line";
+    String UP_LINE_OR_HISTORY = "up-line-or-history";
+    String UP_LINE_OR_SEARCH = "up-line-or-search";
+    String VI_ADD_EOL = "vi-add-eol";
+    String VI_ADD_NEXT = "vi-add-next";
+    String VI_BACKWARD_BLANK_WORD = "vi-backward-blank-word";
+    String VI_BACKWARD_BLANK_WORD_END = "vi-backward-blank-word-end";
+    String VI_BACKWARD_CHAR = "vi-backward-char";
+    String VI_BACKWARD_DELETE_CHAR = "vi-backward-delete-char";
+    String VI_BACKWARD_KILL_WORD = "vi-backward-kill-word";
+    String VI_BACKWARD_WORD = "vi-backward-word";
+    String VI_BACKWARD_WORD_END = "vi-backward-word-end";
+    String VI_BEGINNING_OF_LINE = "vi-beginning-of-line";
+    String VI_CHANGE = "vi-change-to";
+    String VI_CHANGE_EOL = "vi-change-eol";
+    String VI_CHANGE_WHOLE_LINE = "vi-change-whole-line";
+    String VI_CMD_MODE = "vi-cmd-mode";
+    String VI_DELETE = "vi-delete";
+    String VI_DELETE_CHAR = "vi-delete-char";
+    String VI_DIGIT_OR_BEGINNING_OF_LINE = "vi-digit-or-beginning-of-line";
+    String VI_DOWN_LINE_OR_HISTORY = "vi-down-line-or-history";
+    String VI_END_OF_LINE = "vi-end-of-line";
+    String VI_FETCH_HISTORY = "vi-fetch-history";
+    String VI_FIND_NEXT_CHAR = "vi-find-next-char";
+    String VI_FIND_NEXT_CHAR_SKIP = "vi-find-next-char-skip";
+    String VI_FIND_PREV_CHAR = "vi-find-prev-char";
+    String VI_FIND_PREV_CHAR_SKIP = "vi-find-prev-char-skip";
+    String VI_FIRST_NON_BLANK = "vi-first-non-blank";
+    String VI_FORWARD_BLANK_WORD = "vi-forward-blank-word";
+    String VI_FORWARD_BLANK_WORD_END = "vi-forward-blank-word-end";
+    String VI_FORWARD_CHAR = "vi-forward-char";
+    String VI_FORWARD_WORD = "vi-forward-word";
+    String VI_FORWARD_WORD_END = "vi-forward-word-end";
+    String VI_GOTO_COLUMN = "vi-goto-column";
+    String VI_HISTORY_SEARCH_BACKWARD = "vi-history-search-backward";
+    String VI_HISTORY_SEARCH_FORWARD = "vi-history-search-forward";
+    String VI_INSERT = "vi-insert";
+    String VI_INSERT_BOL = "vi-insert-bol";
+    String VI_INSERT_COMMENT = "vi-insert-comment";
+    String VI_JOIN = "vi-join";
+    String VI_KILL_EOL = "vi-kill-eol";
+    String VI_KILL_LINE = "vi-kill-line";
+    String VI_MATCH_BRACKET = "vi-match-bracket";
+    String VI_OPEN_LINE_ABOVE = "vi-open-line-above";
+    String VI_OPEN_LINE_BELOW = "vi-open-line-below";
+    String VI_OPER_SWAP_CASE = "vi-oper-swap-case";
+    String VI_PUT_AFTER = "vi-put-after";
+    String VI_PUT_BEFORE = "vi-put-before";
+    String VI_QUOTED_INSERT = "vi-quoted-insert";
+    String VI_REPEAT_CHANGE = "vi-repeat-change";
+    String VI_REPEAT_FIND = "vi-repeat-find";
+    String VI_REPEAT_SEARCH = "vi-repeat-search";
+    String VI_REPLACE = "vi-replace";
+    String VI_REPLACE_CHARS = "vi-replace-chars";
+    String VI_REV_REPEAT_FIND = "vi-rev-repeat-find";
+    String VI_REV_REPEAT_SEARCH = "vi-rev-repeat-search";
+    String VI_SET_BUFFER = "vi-set-buffer";
+    String VI_SUBSTITUTE = "vi-substitute";
+    String VI_SWAP_CASE = "vi-swap-case";
+    String VI_UNDO_CHANGE = "vi-undo-change";
+    String VI_UP_LINE_OR_HISTORY = "vi-up-line-or-history";
+    String VI_YANK = "vi-yank";
+    String VI_YANK_EOL = "vi-yank-eol";
+    String VI_YANK_WHOLE_LINE = "vi-yank-whole-line";
+    String VISUAL_LINE_MODE = "visual-line-mode";
+    String VISUAL_MODE = "visual-mode";
+    String WHAT_CURSOR_POSITION = "what-cursor-position";
+    String YANK = "yank";
+    String YANK_POP = "yank-pop";
+    String MOUSE = "mouse";
+    String FOCUS_IN = "terminal-focus-in";
+    String FOCUS_OUT = "terminal-focus-out";
+
+    String BEGIN_PASTE = "begin-paste";
+
+    //
+    // KeyMap names
+    //
+
+    String VICMD = "vicmd";
+    String VIINS = "viins";
+    String VIOPP = "viopp";
+    String VISUAL = "visual";
+    String MAIN = "main";
+    String EMACS = "emacs";
+    String SAFE = ".safe";
+    String MENU = "menu";
+
+    //
+    // Variable names
+    //
+
+    String BIND_TTY_SPECIAL_CHARS = "bind-tty-special-chars";
+    String COMMENT_BEGIN = "comment-begin";
+    String BELL_STYLE = "bell-style";
+    String PREFER_VISIBLE_BELL = "prefer-visible-bell";
+    String LIST_MAX = "list-max";
+    String DISABLE_HISTORY = "disable-history";
+    String DISABLE_COMPLETION = "disable-completion";
+    String EDITING_MODE = "editing-mode";
+    String KEYMAP = "keymap";
+    String BLINK_MATCHING_PAREN = "blink-matching-paren";
+    String WORDCHARS = "WORDCHARS";
+    String REMOVE_SUFFIX_CHARS = "REMOVE_SUFFIX_CHARS";
+    String SEARCH_TERMINATORS = "search-terminators";
+    String ERRORS = "errors";
+    /** Property for the "others" group name */
+    String OTHERS_GROUP_NAME = "OTHERS_GROUP_NAME";
+    /** Property for the "original" group name */
+    String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME";
+    /** Completion style for displaying groups name */
+    String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP";
+    /** Completion style for displaying the current selected item */
+    String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION";
+    /** Completion style for displaying the candidate description */
+    String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION";
+    /** Completion style for displaying the matching part of candidates */
+    String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING";
+    /**
+     * Set the template for prompts for secondary (continuation) lines.
+     * This is a prompt template as described in the class header.
+     */
+    String SECONDARY_PROMPT_PATTERN = "secondary-prompt-pattern";
+    /**
+     * When in multiline edit mode, this variable can be used
+     * to offset the line number displayed.
+     */
+    String LINE_OFFSET = "line-offset";
+
+    /**
+     * Timeout for ambiguous key sequences.
+     * If the key sequence is ambiguous, i.e. there is a matching
+     * sequence but the sequence is also a prefix for other bindings,
+     * the next key press will be waited for a specified amount of
+     * time.  If the timeout elapses, the matched sequence will be
+     * used.
+     */
+    String AMBIGUOUS_BINDING = "ambiguous-binding";
+
+    /**
+     * Columns separated list of patterns that will not be saved in history.
+     */
+    String HISTORY_IGNORE = "history-ignore";
+
+    /**
+     * File system history path.
+     */
+    String HISTORY_FILE = "history-file";
+
+    /**
+     * Number of history items to keep in memory.
+     */
+    String HISTORY_SIZE = "history-size";
+
+    /**
+     * Number of history items to keep in the history file.
+     */
+    String HISTORY_FILE_SIZE = "history-file-size";
+
+    Map<String, KeyMap<Binding>> defaultKeyMaps();
+
+    enum Option {
+        COMPLETE_IN_WORD,
+        DISABLE_EVENT_EXPANSION,
+        HISTORY_VERIFY,
+        HISTORY_IGNORE_SPACE(true),
+        HISTORY_IGNORE_DUPS(true),
+        HISTORY_REDUCE_BLANKS(true),
+        HISTORY_BEEP(true),
+        HISTORY_INCREMENTAL(true),
+        HISTORY_TIMESTAMPED(true),
+        /** when displaying candidates, group them by {@link Candidate#group()} */
+        AUTO_GROUP(true),
+        AUTO_MENU(true),
+        AUTO_LIST(true),
+        RECOGNIZE_EXACT,
+        /** display group name before each group (else display all group names first) */
+        GROUP(true),
+        /** if completion is case insensitive or not */
+        CASE_INSENSITIVE,
+        LIST_AMBIGUOUS,
+        LIST_PACKED,
+        LIST_ROWS_FIRST,
+        GLOB_COMPLETE,
+        MENU_COMPLETE,
+        /** if set and not at start of line before prompt, move to new line */
+        AUTO_FRESH_LINE,
+
+        /** After writing into the rightmost column, do we immediately
+         * move to the next line (the default)? Or do we wait until
+         * the next character.
+         * If set, an input line that is exactly {@code N*columns} wide will
+         * use {@code N} screen lines; otherwise it will use {@code N+1} lines.
+         * When the cursor position is the right margin of the last line
+         * (i.e. after {@code N*columns} normal characters), if this option
+         * it set, the cursor will be remain on the last line (line {@code N-1},
+         * zero-origin); if unset the cursor will be on the empty next line.
+         * Regardless, for all except the last screen line if the cursor is at
+         * the right margin, it will be shown at the start of the next line.
+         */
+        DELAY_LINE_WRAP,
+        AUTO_PARAM_SLASH(true),
+        AUTO_REMOVE_SLASH(true),
+        /** When hitting the <code>&lt;tab&gt;</code> key at the beginning of the line, insert a tabulation
+         *  instead of completing.  This is mainly useful when {@link #BRACKETED_PASTE} is
+         *  disabled, so that copy/paste of indented text does not trigger completion.
+         */
+        INSERT_TAB,
+        MOUSE,
+        DISABLE_HIGHLIGHTER,
+        BRACKETED_PASTE(true),
+        /**
+         * Instead of printing a new line when the line is read, the entire line
+         * (including the prompt) will be erased, thereby leaving the screen as it
+         * was before the readLine call.
+         */
+        ERASE_LINE_ON_FINISH,
+
+        /** if history search is fully case insensitive */
+        CASE_INSENSITIVE_SEARCH,
+        ;
+
+        private final boolean def;
+
+        Option() {
+            this(false);
+        }
+
+        Option(boolean def) {
+            this.def = def;
+        }
+
+        public boolean isDef() {
+            return def;
+        }
+    }
+
+    enum RegionType {
+        NONE,
+        CHAR,
+        LINE,
+        PASTE
+    }
+
+    /**
+     * Read the next line and return the contents of the buffer.
+     *
+     * Equivalent to <code>readLine(null, null, null)</code>.
+     *
+     * @return the line read
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine() throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read the next line with the specified character mask. If null, then
+     * characters will be echoed. If 0, then no characters will be echoed.
+     *
+     * Equivalent to <code>readLine(null, mask, null)</code>
+     *
+     * @param mask      The mask character, <code>null</code> or <code>0</code>.
+     * @return          A line that is read from the terminal, can never be null.
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(Character mask) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read the next line with the specified prompt.
+     * If null, then the default prompt will be used.
+     *
+     * Equivalent to <code>readLine(prompt, null, null)</code>
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     * @return          A line that is read from the terminal, can never be null.
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(String prompt) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * Equivalent to <code>readLine(prompt, mask, null)</code>
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     * @param mask      The mask character, <code>null</code> or <code>0</code>.
+     * @return          A line that is read from the terminal, can never be null.
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(String prompt, Character mask) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * Equivalent to <code>readLine(prompt, null, mask, buffer)</code>
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     *   This is a template, with optional {@code '%'} escapes, as
+     *   described in the class header.
+     * @param mask      The character mask, may be null.
+     * @param buffer    The default value presented to the user to edit, may be null.
+     * @return          A line that is read from the terminal, can never be null.
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(String prompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt      The prompt to issue to the terminal, may be null.
+     *   This is a template, with optional {@code '%'} escapes, as
+     *   described in the class header.
+     * @param rightPrompt The right prompt
+     *   This is a template, with optional {@code '%'} escapes, as
+     *   described in the class header.
+     * @param mask        The character mask, may be null.
+     * @param buffer      The default value presented to the user to edit, may be null.
+     * @return            A line that is read from the terminal, can never be null.
+     *
+     * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example)
+     * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
+     * @throws java.io.IOError in case of other i/o errors
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(String prompt, String rightPrompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt      The prompt to issue to the terminal, may be null.
+     *   This is a template, with optional {@code '%'} escapes, as
+     *   described in the class header.
+     * @param rightPrompt The right prompt
+     *   This is a template, with optional {@code '%'} escapes, as
+     *   described in the class header.
+     * @param maskingCallback  The {@link MaskingCallback} to use when displaying lines and adding them to the line {@link History}
+     * @param buffer      The default value presented to the user to edit, may be null.
+     * @return            A line that is read from the terminal, can never be null.
+     *
+     * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example)
+     * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example)
+     * @throws java.io.IOError in case of other i/o errors
+     * @throws UserInterruptException If the call was interrupted by the user.
+     * @throws EndOfFileException     If the end of the input stream was reached.
+     */
+    String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer) throws UserInterruptException, EndOfFileException;
+
+    /**
+     * Prints a line above the prompt and redraw everything.
+     * If the LineReader is not actually reading a line, the string will simply be printed to the terminal.
+     *
+     * @see #printAbove(AttributedString)
+     * @param str the string to print
+     */
+    void printAbove(String str);
+
+    /**
+     * Prints a string before the prompt and redraw everything.
+     * If the LineReader is not actually reading a line, the string will simply be printed to the terminal.
+     *
+     * @see #printAbove(String)
+     * @param str the string to print
+     */
+    void printAbove(AttributedString str);
+
+    /**
+     * Check if a thread is currently in a <code>readLine()</code> call.
+     *
+     * @return <code>true</code> if there is an ongoing <code>readLine()</code> call.
+     */
+    boolean isReading();
+
+    //
+    // Chainable setters
+    //
+
+    LineReader variable(String name, Object value);
+
+    LineReader option(Option option, boolean value);
+
+    void callWidget(String name);
+
+    Map<String, Object> getVariables();
+
+    Object getVariable(String name);
+
+    void setVariable(String name, Object value);
+
+    boolean isSet(Option option);
+
+    void setOpt(Option option);
+
+    void unsetOpt(Option option);
+
+    Terminal getTerminal();
+
+    Map<String, Widget> getWidgets();
+
+    Map<String, Widget> getBuiltinWidgets();
+
+    Buffer getBuffer();
+
+    String getAppName();
+
+    /**
+     * Push back a key sequence that will be later consumed by the line reader.
+     * This method can be used after reading the cursor position using
+     * {@link Terminal#getCursorPosition(IntConsumer)}.
+     *
+     * @param macro the key sequence to push back
+     * @see Terminal#getCursorPosition(IntConsumer)
+     * @see #readMouseEvent()
+     */
+    void runMacro(String macro);
+
+    /**
+     * Read a mouse event when the {@link org.jline.utils.InfoCmp.Capability#key_mouse} sequence
+     * has just been read on the input stream.
+     * Compared to {@link Terminal#readMouseEvent()}, this method takes into account keys
+     * that have been pushed back using {@link #runMacro(String)}.
+     *
+     * @return the mouse event
+     * @see #runMacro(String)
+     * @see Terminal#getCursorPosition(IntConsumer)
+     */
+    MouseEvent readMouseEvent();
+
+    History getHistory();
+
+    Parser getParser();
+
+    Highlighter getHighlighter();
+
+    Expander getExpander();
+
+    Map<String, KeyMap<Binding>> getKeyMaps();
+
+    String getKeyMap();
+
+    boolean setKeyMap(String name);
+
+    KeyMap<Binding> getKeys();
+
+    ParsedLine getParsedLine();
+
+    String getSearchTerm();
+
+    RegionType getRegionActive();
+
+    int getRegionMark();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import jdk.internal.org.jline.reader.impl.LineReaderImpl;
+import jdk.internal.org.jline.reader.impl.history.DefaultHistory;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.TerminalBuilder;
+import jdk.internal.org.jline.utils.Log;
+
+public final class LineReaderBuilder {
+
+    public static LineReaderBuilder builder() {
+        return new LineReaderBuilder();
+    }
+
+    Terminal terminal;
+    String appName;
+    Map<String, Object> variables = new HashMap<>();
+    Map<LineReader.Option, Boolean> options = new HashMap<>();
+    History history;
+    Completer completer;
+    History memoryHistory;
+    Highlighter highlighter;
+    Parser parser;
+    Expander expander;
+
+    private LineReaderBuilder() {
+    }
+
+    public LineReaderBuilder terminal(Terminal terminal) {
+        this.terminal = terminal;
+        return this;
+    }
+
+    public LineReaderBuilder appName(String appName) {
+        this.appName = appName;
+        return this;
+    }
+
+    public LineReaderBuilder variables(Map<String, Object> variables) {
+        Map<String, Object> old = this.variables;
+        this.variables = Objects.requireNonNull(variables);
+        this.variables.putAll(old);
+        return this;
+    }
+
+    public LineReaderBuilder variable(String name, Object value) {
+        this.variables.put(name, value);
+        return this;
+    }
+
+    public LineReaderBuilder option(LineReader.Option option, boolean value) {
+        this.options.put(option, value);
+        return this;
+    }
+
+    public LineReaderBuilder history(History history) {
+        this.history = history;
+        return this;
+    }
+
+    public LineReaderBuilder completer(Completer completer) {
+        this.completer = completer;
+        return this;
+    }
+
+    public LineReaderBuilder highlighter(Highlighter highlighter) {
+        this.highlighter = highlighter;
+        return this;
+    }
+
+    public LineReaderBuilder parser(Parser parser) {
+        if (parser != null) {
+            try {
+                if (!Boolean.parseBoolean(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.");
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        this.parser = parser;
+        return this;
+    }
+
+    public LineReaderBuilder expander(Expander expander) {
+        this.expander = expander;
+        return this;
+    }
+
+    public LineReader build() {
+        Terminal terminal = this.terminal;
+        if (terminal == null) {
+            try {
+                terminal = TerminalBuilder.terminal();
+            } catch (IOException e) {
+                throw new IOError(e);
+            }
+        }
+        LineReaderImpl reader = new LineReaderImpl(terminal, appName, variables);
+        if (history != null) {
+            reader.setHistory(history);
+        } else {
+            if (memoryHistory == null) {
+                memoryHistory = new DefaultHistory();
+            }
+            reader.setHistory(memoryHistory);
+        }
+        if (completer != null) {
+            reader.setCompleter(completer);
+        }
+        if (highlighter != null) {
+            reader.setHighlighter(highlighter);
+        }
+        if (parser != null) {
+            reader.setParser(parser);
+        }
+        if (expander != null) {
+            reader.setExpander(expander);
+        }
+        for (Map.Entry<LineReader.Option, Boolean> e : options.entrySet()) {
+            reader.option(e.getKey(), e.getValue());
+        }
+        return reader;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Macro.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+public class Macro implements Binding {
+
+    private final String sequence;
+
+    public Macro(String sequence) {
+        this.sequence = sequence;
+    }
+
+    public String getSequence() {
+        return sequence;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Macro macro = (Macro) o;
+        return sequence.equals(macro.sequence);
+    }
+
+    @Override
+    public int hashCode() {
+        return sequence.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "Macro[" +
+                sequence + ']';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/MaskingCallback.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * Callback used to mask parts of the line
+ */
+public interface MaskingCallback {
+
+    /**
+     * Transforms the line before it is displayed so that
+     * some parts can be hidden.
+     *
+     * @param line the current line being edited
+     * @return the modified line to display
+     */
+    String display(String line);
+
+    /**
+     * Transforms the line before storing in the history.
+     * If the return value is empty or null, it will not be saved
+     * in the history.
+     *
+     * @param line the line to be added to history
+     * @return the modified line
+     */
+    String history(String line);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ParsedLine.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader;
+
+import java.util.List;
+
+/**
+ * <code>ParsedLine</code> objects are returned by the {@link Parser}
+ * during completion or when accepting the line.
+ *
+ * The instances should implement the {@link CompletingParsedLine}
+ * interface so that escape chars and quotes can be correctly handled.
+ *
+ * @see Parser
+ * @see CompletingParsedLine
+ */
+public interface ParsedLine {
+
+    /**
+     * The current word being completed.
+     * If the cursor is after the last word, an empty string is returned.
+     *
+     * @return the word being completed or an empty string
+     */
+    String word();
+
+    /**
+     * The cursor position within the current word.
+     *
+     * @return the cursor position within the current word
+     */
+    int wordCursor();
+
+    /**
+     * The index of the current word in the list of words.
+     *
+     * @return the index of the current word in the list of words
+     */
+    int wordIndex();
+
+    /**
+     * The list of words.
+     *
+     * @return the list of words
+     */
+    List<String> words();
+
+    /**
+     * The unparsed line.
+     *
+     * @return the unparsed line
+     */
+    String line();
+
+    /**
+     * The cursor position within the line.
+     *
+     * @return the cursor position within the line
+     */
+    int cursor();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+public interface Parser {
+
+    ParsedLine parse(String line, int cursor, ParseContext context) throws SyntaxError;
+
+    default ParsedLine parse(String line, int cursor) throws SyntaxError {
+        return parse(line, cursor, ParseContext.UNSPECIFIED);
+    }
+
+    enum ParseContext {
+        UNSPECIFIED,
+
+        /** Try a real "final" parse.
+         * May throw EOFError in which case we have incomplete input.
+         */
+        ACCEPT_LINE,
+
+        /** Parse to find completions (typically after a Tab).
+         * We should tolerate and ignore errors.
+         */
+        COMPLETE,
+
+        /** Called when we need to update the secondary prompts.
+         * Specifically, when we need the 'missing' field from EOFError,
+         * which is used by a "%M" in a prompt pattern.
+         */
+        SECONDARY_PROMPT
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Reference.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * A reference to a {@link Widget}.
+ */
+public class Reference implements Binding {
+
+    private final String name;
+
+    public Reference(String name) {
+        this.name = name;
+    }
+
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Reference func = (Reference) o;
+        return name.equals(func.name);
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "Reference[" +
+                name + ']';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/SyntaxError.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package jdk.internal.org.jline.reader;
+
+public class SyntaxError extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final int line;
+    private final int column;
+
+    public SyntaxError(int line, int column, String message) {
+        super(message);
+        this.line = line;
+        this.column = column;
+    }
+
+    public int column() {
+        return column;
+    }
+
+    public int line() {
+        return line;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/UserInterruptException.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ * This exception is thrown by {@link LineReader#readLine} when
+ * user interrupt handling is enabled and the user types the
+ * interrupt character (ctrl-C). The partially entered line is
+ * available via the {@link #getPartialLine()} method.
+ */
+public class UserInterruptException
+    extends RuntimeException
+{
+    private static final long serialVersionUID = 6172232572140736750L;
+
+    private final String partialLine;
+
+    public UserInterruptException(String partialLine)
+    {
+        this.partialLine = partialLine;
+    }
+
+    /**
+     * @return the partially entered line when ctrl-C was pressed
+     */
+    public String getPartialLine()
+    {
+        return partialLine;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Widget.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,19 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader;
+
+/**
+ *
+ */
+@FunctionalInterface
+public interface Widget extends Binding {
+
+    boolean apply();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/BufferImpl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import java.util.Objects;
+
+import jdk.internal.org.jline.reader.Buffer;
+
+/**
+ * A holder for a {@link StringBuilder} that also contains the current cursor position.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class BufferImpl implements Buffer
+{
+    private int cursor = 0;
+    private int cursorCol = -1;
+    private int[] buffer;
+    private int g0;
+    private int g1;
+
+    public BufferImpl() {
+        this(64);
+    }
+
+    public BufferImpl(int size) {
+        buffer = new int[size];
+        g0 = 0;
+        g1 = buffer.length;
+    }
+
+    private BufferImpl(BufferImpl buffer) {
+        this.cursor = buffer.cursor;
+        this.cursorCol = buffer.cursorCol;
+        this.buffer = buffer.buffer.clone();
+        this.g0 = buffer.g0;
+        this.g1 = buffer.g1;
+    }
+
+    public BufferImpl copy () {
+        return new BufferImpl(this);
+    }
+
+    public int cursor() {
+        return cursor;
+    }
+
+    public int length() {
+        return buffer.length - (g1 - g0);
+    }
+
+    public boolean currChar(int ch) {
+        if (cursor == length()) {
+            return false;
+        } else {
+            buffer[adjust(cursor)] = ch;
+            return true;
+        }
+    }
+
+    public int currChar() {
+        if (cursor == length()) {
+            return 0;
+        } else {
+            return atChar(cursor);
+        }
+    }
+
+    public int prevChar() {
+        if (cursor <= 0) {
+            return 0;
+        }
+        return atChar(cursor - 1);
+    }
+
+    public int nextChar() {
+        if (cursor >= length() - 1) {
+            return 0;
+        }
+        return atChar(cursor + 1);
+    }
+
+    public int atChar(int i) {
+        if (i < 0 || i >= length()) {
+            return 0;
+        }
+        return buffer[adjust(i)];
+    }
+
+    private int adjust(int i) {
+        return (i >= g0) ? i + g1 - g0 : i;
+    }
+
+    /**
+     * Write the specific character into the buffer, setting the cursor position
+     * ahead one.
+     *
+     * @param c the character to insert
+     */
+    public void write(int c) {
+        write(new int[] { c });
+    }
+
+    /**
+     * Write the specific character into the buffer, setting the cursor position
+     * ahead one. The text may overwrite or insert based on the current setting
+     * of {@code overTyping}.
+     *
+     * @param c the character to insert
+     */
+    public void write(int c, boolean overTyping) {
+        if (overTyping) {
+            delete(1);
+        }
+        write(new int[] { c });
+    }
+
+    /**
+     * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
+     */
+    public void write(CharSequence str) {
+        Objects.requireNonNull(str);
+        write(str.codePoints().toArray());
+    }
+
+    public void write(CharSequence str, boolean overTyping) {
+        Objects.requireNonNull(str);
+        int[] ucps = str.codePoints().toArray();
+        if (overTyping) {
+            delete(ucps.length);
+        }
+        write(ucps);
+    }
+
+    private void write(int[] ucps) {
+        moveGapToCursor();
+        int len = length() + ucps.length;
+        int sz = buffer.length;
+        if (sz < len) {
+            while (sz < len) {
+                sz *= 2;
+            }
+            int[] nb = new int[sz];
+            System.arraycopy(buffer, 0, nb, 0, g0);
+            System.arraycopy(buffer, g1, nb, g1 + sz - buffer.length, buffer.length - g1);
+            g1 += sz - buffer.length;
+            buffer = nb;
+        }
+        System.arraycopy(ucps, 0, buffer, cursor, ucps.length);
+        g0 += ucps.length;
+        cursor += ucps.length;
+        cursorCol = -1;
+    }
+
+    public boolean clear() {
+        if (length() == 0) {
+            return false;
+        }
+        g0 = 0;
+        g1 = buffer.length;
+        cursor = 0;
+        cursorCol = -1;
+        return true;
+    }
+
+    public String substring(int start) {
+        return substring(start, length());
+    }
+
+    public String substring(int start, int end) {
+        if (start >= end || start < 0 || end > length()) {
+            return "";
+        }
+        if (end <= g0) {
+            return new String(buffer, start, end - start);
+        } else if (start > g0) {
+            return new String(buffer, g1 - g0 + start, end - start);
+        } else {
+            int[] b = buffer.clone();
+            System.arraycopy(b, g1, b, g0, b.length - g1);
+            return new String(b, start, end - start);
+        }
+    }
+
+    public String upToCursor() {
+        return substring(0, cursor);
+    }
+
+    /**
+     * Move the cursor position to the specified absolute index.
+     */
+    public boolean cursor(int position) {
+        if (position == cursor) {
+            return true;
+        }
+        return move(position - cursor) != 0;
+    }
+
+    /**
+     * Move the cursor <i>where</i> characters.
+     *
+     * @param num   If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
+     * @return      The number of spaces we moved
+     */
+    public int move(final int num) {
+        int where = num;
+
+        if ((cursor == 0) && (where <= 0)) {
+            return 0;
+        }
+
+        if ((cursor == length()) && (where >= 0)) {
+            return 0;
+        }
+
+        if ((cursor + where) < 0) {
+            where = -cursor;
+        }
+        else if ((cursor + where) > length()) {
+            where = length() - cursor;
+        }
+
+        cursor += where;
+        cursorCol = -1;
+
+        return where;
+    }
+
+    public boolean up() {
+        int col = getCursorCol();
+        int pnl = cursor - 1;
+        while (pnl >= 0 && atChar(pnl) != '\n') {
+            pnl--;
+        }
+        if (pnl < 0) {
+            return false;
+        }
+        int ppnl = pnl - 1;
+        while (ppnl >= 0 && atChar(ppnl) != '\n') {
+            ppnl--;
+        }
+        cursor = Math.min(ppnl + col + 1, pnl);
+        return true;
+    }
+
+    public boolean down() {
+        int col = getCursorCol();
+        int nnl = cursor;
+        while (nnl < length() && atChar(nnl) != '\n') {
+            nnl++;
+        }
+        if (nnl >= length()) {
+            return false;
+        }
+        int nnnl = nnl + 1;
+        while (nnnl < length() && atChar(nnnl) != '\n') {
+            nnnl++;
+        }
+        cursor = Math.min(nnl + col + 1, nnnl);
+        return true;
+    }
+
+    public boolean moveXY(int dx, int dy) {
+        int col = 0;
+        while (prevChar() != '\n' && move(-1) == -1) {
+            col++;
+        }
+        cursorCol = 0;
+        while (dy < 0) {
+            up();
+            dy++;
+        }
+        while (dy > 0) {
+            down();
+            dy--;
+        }
+        col = Math.max(col + dx, 0);
+        for (int i = 0; i < col; i++) {
+            if (move(1) != 1 || currChar() == '\n') {
+                break;
+            }
+        }
+        cursorCol = col;
+        return true;
+    }
+
+    private int getCursorCol() {
+        if (cursorCol < 0) {
+            cursorCol = 0;
+            int pnl = cursor - 1;
+            while (pnl >= 0 && atChar(pnl) != '\n') {
+                pnl--;
+            }
+            cursorCol = cursor - pnl - 1;
+        }
+        return cursorCol;
+    }
+
+    /**
+     * Issue <em>num</em> backspaces.
+     *
+     * @return the number of characters backed up
+     */
+    public int backspace(final int num) {
+        int count = Math.max(Math.min(cursor, num), 0);
+        moveGapToCursor();
+        cursor -= count;
+        g0 -= count;
+        cursorCol = -1;
+        return count;
+    }
+
+    /**
+     * Issue a backspace.
+     *
+     * @return true if successful
+     */
+    public boolean backspace() {
+        return backspace(1) == 1;
+    }
+
+    public int delete(int num) {
+        int count = Math.max(Math.min(length() - cursor, num), 0);
+        moveGapToCursor();
+        g1 += count;
+        cursorCol = -1;
+        return count;
+    }
+
+    public boolean delete() {
+        return delete(1) == 1;
+    }
+
+    @Override
+    public String toString() {
+        return substring(0, length());
+    }
+
+    public void copyFrom(Buffer buf) {
+        if (!(buf instanceof BufferImpl)) {
+            throw new IllegalStateException();
+        }
+        BufferImpl that = (BufferImpl) buf;
+        this.g0 = that.g0;
+        this.g1 = that.g1;
+        this.buffer = that.buffer.clone();
+        this.cursor = that.cursor;
+        this.cursorCol = that.cursorCol;
+    }
+
+    private void moveGapToCursor() {
+        if (cursor < g0) {
+            int l = g0 - cursor;
+            System.arraycopy(buffer, cursor, buffer, g1 - l, l);
+            g0 -= l;
+            g1 -= l;
+        } else if (cursor > g0) {
+            int l = cursor - g0;
+            System.arraycopy(buffer, g1, buffer, g0, l);
+            g0 += l;
+            g1 += l;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultExpander.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,207 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import java.util.ListIterator;
+
+import jdk.internal.org.jline.reader.Expander;
+import jdk.internal.org.jline.reader.History;
+import jdk.internal.org.jline.reader.History.Entry;
+
+public class DefaultExpander implements Expander {
+
+    /**
+     * Expand event designator such as !!, !#, !3, etc...
+     * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
+     */
+    @SuppressWarnings("fallthrough")
+    @Override
+    public String expandHistory(History history, String line) {
+        boolean inQuote = false;
+        StringBuilder sb = new StringBuilder();
+        boolean escaped = false;
+        int unicode = 0;
+        for (int i = 0; i < line.length(); i++) {
+            char c = line.charAt(i);
+            if (unicode > 0) {
+                escaped = (--unicode >= 0);
+                sb.append(c);
+            }
+            else if (escaped) {
+                if (c == 'u') {
+                    unicode = 4;
+                } else {
+                    escaped = false;
+                }
+                sb.append(c);
+            }
+            else if (c == '\'') {
+                inQuote = !inQuote;
+                sb.append(c);
+            }
+            else if (inQuote) {
+                sb.append(c);
+            }
+            else {
+                switch (c) {
+                    case '\\':
+                        // any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
+                        // a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
+                        // otherwise, add the escape
+                        escaped = true;
+                        sb.append(c);
+                        break;
+                    case '!':
+                        if (i + 1 < line.length()) {
+                            c = line.charAt(++i);
+                            boolean neg = false;
+                            String rep = null;
+                            int i1, idx;
+                            switch (c) {
+                                case '!':
+                                    if (history.size() == 0) {
+                                        throw new IllegalArgumentException("!!: event not found");
+                                    }
+                                    rep = history.get(history.index() - 1);
+                                    break;
+                                case '#':
+                                    sb.append(sb.toString());
+                                    break;
+                                case '?':
+                                    i1 = line.indexOf('?', i + 1);
+                                    if (i1 < 0) {
+                                        i1 = line.length();
+                                    }
+                                    String sc = line.substring(i + 1, i1);
+                                    i = i1;
+                                    idx = searchBackwards(history, sc, history.index(), false);
+                                    if (idx < 0) {
+                                        throw new IllegalArgumentException("!?" + sc + ": event not found");
+                                    } else {
+                                        rep = history.get(idx);
+                                    }
+                                    break;
+                                case '$':
+                                    if (history.size() == 0) {
+                                        throw new IllegalArgumentException("!$: event not found");
+                                    }
+                                    String previous = history.get(history.index() - 1).trim();
+                                    int lastSpace = previous.lastIndexOf(' ');
+                                    if (lastSpace != -1) {
+                                        rep = previous.substring(lastSpace + 1);
+                                    } else {
+                                        rep = previous;
+                                    }
+                                    break;
+                                case ' ':
+                                case '\t':
+                                    sb.append('!');
+                                    sb.append(c);
+                                    break;
+                                case '-':
+                                    neg = true;
+                                    i++;
+                                    // fall through
+                                case '0':
+                                case '1':
+                                case '2':
+                                case '3':
+                                case '4':
+                                case '5':
+                                case '6':
+                                case '7':
+                                case '8':
+                                case '9':
+                                    i1 = i;
+                                    for (; i < line.length(); i++) {
+                                        c = line.charAt(i);
+                                        if (c < '0' || c > '9') {
+                                            break;
+                                        }
+                                    }
+                                    try {
+                                        idx = Integer.parseInt(line.substring(i1, i));
+                                    } catch (NumberFormatException e) {
+                                        throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
+                                    }
+                                    if (neg && idx > 0 && idx <= history.size()) {
+                                        rep = history.get(history.index() - idx);
+                                    } else if (!neg && idx > history.index() - history.size() && idx <= history.index()) {
+                                        rep = history.get(idx - 1);
+                                    } else {
+                                        throw new IllegalArgumentException((neg ? "!-" : "!") + line.substring(i1, i) + ": event not found");
+                                    }
+                                    break;
+                                default:
+                                    String ss = line.substring(i);
+                                    i = line.length();
+                                    idx = searchBackwards(history, ss, history.index(), true);
+                                    if (idx < 0) {
+                                        throw new IllegalArgumentException("!" + ss + ": event not found");
+                                    } else {
+                                        rep = history.get(idx);
+                                    }
+                                    break;
+                            }
+                            if (rep != null) {
+                                sb.append(rep);
+                            }
+                        } else {
+                            sb.append(c);
+                        }
+                        break;
+                    case '^':
+                        if (i == 0) {
+                            int i1 = line.indexOf('^', i + 1);
+                            int i2 = line.indexOf('^', i1 + 1);
+                            if (i2 < 0) {
+                                i2 = line.length();
+                            }
+                            if (i1 > 0 && i2 > 0) {
+                                String s1 = line.substring(i + 1, i1);
+                                String s2 = line.substring(i1 + 1, i2);
+                                String s = history.get(history.index() - 1).replace(s1, s2);
+                                sb.append(s);
+                                i = i2 + 1;
+                                break;
+                            }
+                        }
+                        sb.append(c);
+                        break;
+                    default:
+                        sb.append(c);
+                        break;
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String expandVar(String word) {
+        return word;
+    }
+
+    protected int searchBackwards(History history, String searchTerm, int startIndex, boolean startsWith) {
+        ListIterator<Entry> it = history.iterator(startIndex);
+        while (it.hasPrevious()) {
+            History.Entry e = it.previous();
+            if (startsWith) {
+                if (e.line().startsWith(searchTerm)) {
+                    return e.index();
+                }
+            } else {
+                if (e.line().contains(searchTerm)) {
+                    return e.index();
+                }
+            }
+        }
+        return -1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,84 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.LineReader.RegionType;
+import jdk.internal.org.jline.reader.Highlighter;
+import jdk.internal.org.jline.utils.AttributedString;
+import jdk.internal.org.jline.utils.AttributedStringBuilder;
+import jdk.internal.org.jline.utils.AttributedStyle;
+import jdk.internal.org.jline.utils.WCWidth;
+
+public class DefaultHighlighter implements Highlighter {
+
+    @Override
+    public AttributedString highlight(LineReader reader, String buffer) {
+        int underlineStart = -1;
+        int underlineEnd = -1;
+        int negativeStart = -1;
+        int negativeEnd = -1;
+        String search = reader.getSearchTerm();
+        if (search != null && search.length() > 0) {
+            underlineStart = buffer.indexOf(search);
+            if (underlineStart >= 0) {
+                underlineEnd = underlineStart + search.length() - 1;
+            }
+        }
+        if (reader.getRegionActive() != RegionType.NONE) {
+            negativeStart = reader.getRegionMark();
+            negativeEnd = reader.getBuffer().cursor();
+            if (negativeStart > negativeEnd) {
+                int x = negativeEnd;
+                negativeEnd = negativeStart;
+                negativeStart = x;
+            }
+            if (reader.getRegionActive() == RegionType.LINE) {
+                while (negativeStart > 0 && reader.getBuffer().atChar(negativeStart - 1) != '\n') {
+                    negativeStart--;
+                }
+                while (negativeEnd < reader.getBuffer().length() - 1 && reader.getBuffer().atChar(negativeEnd + 1) != '\n') {
+                    negativeEnd++;
+                }
+            }
+        }
+
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        for (int i = 0; i < buffer.length(); i++) {
+            if (i == underlineStart) {
+                sb.style(AttributedStyle::underline);
+            }
+            if (i == negativeStart) {
+                sb.style(AttributedStyle::inverse);
+            }
+            char c = buffer.charAt(i);
+            if (c == '\t' || c == '\n') {
+                sb.append(c);
+            } else if (c < 32) {
+                sb.style(AttributedStyle::inverseNeg)
+                        .append('^')
+                        .append((char) (c + '@'))
+                        .style(AttributedStyle::inverseNeg);
+            } else {
+                int w = WCWidth.wcwidth(c);
+                if (w > 0) {
+                    sb.append(c);
+                }
+            }
+            if (i == underlineEnd) {
+                sb.style(AttributedStyle::underlineOff);
+            }
+            if (i == negativeEnd) {
+                sb.style(AttributedStyle::inverseOff);
+            }
+        }
+        return sb.toAttributedString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import java.util.*;
+import java.util.function.Predicate;
+
+import jdk.internal.org.jline.reader.CompletingParsedLine;
+import jdk.internal.org.jline.reader.EOFError;
+import jdk.internal.org.jline.reader.ParsedLine;
+import jdk.internal.org.jline.reader.Parser;
+
+public class DefaultParser implements Parser {
+
+    private char[] quoteChars = {'\'', '"'};
+
+    private char[] escapeChars = {'\\'};
+
+    private boolean eofOnUnclosedQuote;
+
+    private boolean eofOnEscapedNewLine;
+
+    //
+    // Chainable setters
+    //
+
+    public DefaultParser quoteChars(final char[] chars) {
+        this.quoteChars = chars;
+        return this;
+    }
+
+    public DefaultParser escapeChars(final char[] chars) {
+        this.escapeChars = chars;
+        return this;
+    }
+
+    public DefaultParser eofOnUnclosedQuote(boolean eofOnUnclosedQuote) {
+        this.eofOnUnclosedQuote = eofOnUnclosedQuote;
+        return this;
+    }
+
+    public DefaultParser eofOnEscapedNewLine(boolean eofOnEscapedNewLine) {
+        this.eofOnEscapedNewLine = eofOnEscapedNewLine;
+        return this;
+    }
+
+    //
+    // Java bean getters and setters
+    //
+
+    public void setQuoteChars(final char[] chars) {
+        this.quoteChars = chars;
+    }
+
+    public char[] getQuoteChars() {
+        return this.quoteChars;
+    }
+
+    public void setEscapeChars(final char[] chars) {
+        this.escapeChars = chars;
+    }
+
+    public char[] getEscapeChars() {
+        return this.escapeChars;
+    }
+
+    public void setEofOnUnclosedQuote(boolean eofOnUnclosedQuote) {
+        this.eofOnUnclosedQuote = eofOnUnclosedQuote;
+    }
+
+    public boolean isEofOnUnclosedQuote() {
+        return eofOnUnclosedQuote;
+    }
+
+    public void setEofOnEscapedNewLine(boolean eofOnEscapedNewLine) {
+        this.eofOnEscapedNewLine = eofOnEscapedNewLine;
+    }
+
+    public boolean isEofOnEscapedNewLine() {
+        return eofOnEscapedNewLine;
+    }
+
+    public ParsedLine parse(final String line, final int cursor, ParseContext context) {
+        List<String> words = new LinkedList<>();
+        StringBuilder current = new StringBuilder();
+        int wordCursor = -1;
+        int wordIndex = -1;
+        int quoteStart = -1;
+        int rawWordCursor = -1;
+        int rawWordLength = -1;
+        int rawWordStart = 0;
+
+        for (int i = 0; (line != null) && (i < line.length()); i++) {
+            // once we reach the cursor, set the
+            // position of the selected index
+            if (i == cursor) {
+                wordIndex = words.size();
+                // the position in the current argument is just the
+                // length of the current argument
+                wordCursor = current.length();
+                rawWordCursor = i - rawWordStart;
+            }
+
+            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
+                    words.add(current.toString());
+                    current.setLength(0);
+                    quoteStart = -1;
+                    if (rawWordCursor >= 0 && rawWordLength < 0) {
+                        rawWordLength = i - rawWordStart + 1;
+                    }
+                } else {
+                    if (!isEscapeChar(line, i)) {
+                        // Take the next character
+                        current.append(line.charAt(i));
+                    }
+                }
+            } 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 (current.length() > 0 || cursor == line.length()) {
+            words.add(current.toString());
+            if (rawWordCursor >= 0 && rawWordLength < 0) {
+                rawWordLength = line.length() - rawWordStart;
+            }
+        }
+
+        if (cursor == line.length()) {
+            wordIndex = words.size() - 1;
+            wordCursor = words.get(words.size() - 1).length();
+            rawWordCursor = cursor - rawWordStart;
+            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");
+        }
+
+        String openingQuote = quoteStart >= 0 ? 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
+     * returns true from {@link #isDelimiterChar}.
+     *
+     * @param buffer    The complete command buffer
+     * @param pos       The index of the character in the buffer
+     * @return          True if the character should be a delimiter
+     */
+    public boolean isDelimiter(final CharSequence buffer, final int pos) {
+        return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+    }
+
+    public boolean isQuoted(final CharSequence buffer, final int pos) {
+        return false;
+    }
+
+    public boolean isQuoteChar(final CharSequence buffer, final int pos) {
+        if (pos < 0) {
+            return false;
+        }
+        if (quoteChars != null) {
+            for (char e : quoteChars) {
+                if (e == buffer.charAt(pos)) {
+                    return !isEscaped(buffer, pos);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if this character is a valid escape char (i.e. one that has not been escaped)
+     *
+     * @param buffer
+     *          the buffer to check in
+     * @param pos
+     *          the position of the character to check
+     * @return true if the character at the specified position in the given buffer is an escape
+     *         character and the character immediately preceding it is not an escape character.
+     */
+    public boolean isEscapeChar(final CharSequence buffer, final int pos) {
+        if (pos < 0) {
+            return false;
+        }
+        if (escapeChars != null) {
+            for (char e : escapeChars) {
+                if (e == buffer.charAt(pos)) {
+                    return !isEscaped(buffer, pos);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if a character is escaped (i.e. if the previous character is an escape)
+     *
+     * @param buffer
+     *          the buffer to check in
+     * @param pos
+     *          the position of the character to check
+     * @return true if the character at the specified position in the given buffer is an escape
+     *         character and the character immediately preceding it is an escape character.
+     */
+    public boolean isEscaped(final CharSequence buffer, final int pos) {
+        if (pos <= 0) {
+            return false;
+        }
+        return isEscapeChar(buffer, pos - 1);
+    }
+
+    /**
+     * 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
+     * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
+     *
+     * @param buffer
+     *          the buffer to check in
+     * @param pos
+     *          the position of the character to check
+     * @return true if the character at the specified position in the given buffer is a delimiter.
+     */
+    public boolean isDelimiterChar(CharSequence buffer, int pos) {
+        return Character.isWhitespace(buffer.charAt(pos));
+    }
+
+    private boolean isRawEscapeChar(char key) {
+        if (escapeChars != null) {
+            for (char e : escapeChars) {
+                if (e == key) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean isRawQuoteChar(char key) {
+        if (quoteChars != null) {
+            for (char e : quoteChars) {
+                if (e == key) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * The result of a delimited buffer.
+     *
+     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+     */
+    public class ArgumentList implements ParsedLine, CompletingParsedLine
+    {
+        private final String line;
+
+        private final List<String> words;
+
+        private final int wordIndex;
+
+        private final int wordCursor;
+
+        private final int cursor;
+
+        private final String openingQuote;
+
+        private final int rawWordCursor;
+
+        private final int rawWordLength;
+
+        @Deprecated
+        public ArgumentList(final String line, final List<String> words,
+                            final int wordIndex, final int wordCursor,
+                            final int cursor) {
+            this(line, words, wordIndex, wordCursor, cursor,
+                    null, wordCursor, words.get(wordIndex).length());
+        }
+
+        /**
+         *
+         * @param line the command line being edited
+         * @param words the list of words
+         * @param wordIndex the index of the current word in the list of words
+         * @param wordCursor the cursor position within the current word
+         * @param cursor the cursor position within the line
+         * @param openingQuote the opening quote (usually '\"' or '\'') or null
+         * @param rawWordCursor the cursor position inside the raw word (i.e. including quotes and escape characters)
+         * @param rawWordLength the raw word length, including quotes and escape characters
+         */
+        public ArgumentList(final String line, final List<String> words,
+                            final int wordIndex, final int wordCursor,
+                            final int cursor, final String openingQuote,
+                            final int rawWordCursor, final int rawWordLength) {
+            this.line = line;
+            this.words = Collections.unmodifiableList(Objects.requireNonNull(words));
+            this.wordIndex = wordIndex;
+            this.wordCursor = wordCursor;
+            this.cursor = cursor;
+            this.openingQuote = openingQuote;
+            this.rawWordCursor = rawWordCursor;
+            this.rawWordLength = rawWordLength;
+        }
+
+        public int wordIndex() {
+            return this.wordIndex;
+        }
+
+        public String word() {
+            // TODO: word() should always be contained in words()
+            if ((wordIndex < 0) || (wordIndex >= words.size())) {
+                return "";
+            }
+            return words.get(wordIndex);
+        }
+
+        public int wordCursor() {
+            return this.wordCursor;
+        }
+
+        public List<String> words() {
+            return this.words;
+        }
+
+        public int cursor() {
+            return this.cursor;
+        }
+
+        public String line() {
+            return line;
+        }
+
+        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]);
+                }
+            }
+            if (openingQuote != null) {
+                sb.insert(0, openingQuote);
+                if (complete) {
+                    sb.append(openingQuote);
+                }
+            }
+            return sb;
+        }
+
+        @Override
+        public int rawWordCursor() {
+            return rawWordCursor;
+        }
+
+        @Override
+        public int rawWordLength() {
+            return rawWordLength;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/KillRing.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl;
+
+/**
+ * The kill ring class keeps killed text in a fixed size ring. In this
+ * class we also keep record of whether or not the last command was a
+ * kill or a yank. Depending on this, the class may behave
+ * different. For instance, two consecutive kill-word commands fill
+ * the same slot such that the next yank will return the two
+ * previously killed words instead that only the last one. Likewise
+ * yank pop requires that the previous command was either a yank or a
+ * yank-pop.
+ */
+public final class KillRing {
+
+    /**
+     * Default size is 60, like in emacs.
+     */
+    private static final int DEFAULT_SIZE = 60;
+
+    private final String[] slots;
+    private int head = 0;
+    private boolean lastKill = false;
+    private boolean lastYank = false;
+
+    /**
+     * Creates a new kill ring of the given size.
+     *
+     * @param size the size of the ring
+     */
+    public KillRing(int size) {
+        slots = new String[size];
+    }
+
+    /**
+     * Creates a new kill ring of the default size. See {@link #DEFAULT_SIZE}.
+     */
+    public KillRing() {
+        this(DEFAULT_SIZE);
+    }
+
+    /**
+     * Resets the last-yank state.
+     */
+    public void resetLastYank() {
+        lastYank = false;
+    }
+
+    /**
+     * Resets the last-kill state.
+     */
+    public void resetLastKill() {
+        lastKill = false;
+    }
+
+    /**
+     * Returns {@code true} if the last command was a yank.
+     * @return {@code true} if the last command was a yank
+     */
+    public boolean lastYank() {
+        return lastYank;
+    }
+
+    /**
+     * Adds the string to the kill-ring. Also sets lastYank to false
+     * and lastKill to true.
+     * @param str the string to add
+     */
+    public void add(String str) {
+        lastYank = false;
+
+        if (lastKill) {
+            if (slots[head] != null) {
+                slots[head] += str;
+                return;
+            }
+        }
+
+        lastKill = true;
+        next();
+        slots[head] = str;
+    }
+
+    /**
+     * Adds the string to the kill-ring product of killing
+     * backwards. If the previous command was a kill text one then
+     * adds the text at the beginning of the previous kill to avoid
+     * that two consecutive backwards kills followed by a yank leaves
+     * things reversed.
+     * @param str the string to add
+     */
+    public void addBackwards(String str) {
+        lastYank = false;
+
+        if (lastKill) {
+            if (slots[head] != null) {
+                slots[head] = str + slots[head];
+                return;
+            }
+        }
+
+        lastKill = true;
+        next();
+        slots[head] = str;
+    }
+
+    /**
+     * Yanks a previously killed text. Returns {@code null} if the
+     * ring is empty.
+     * @return the text in the current position
+     */
+    public String yank() {
+        lastKill = false;
+        lastYank = true;
+        return slots[head];
+    }
+
+    /**
+     * Moves the pointer to the current slot back and returns the text
+     * in that position. If the previous command was not yank returns
+     * null.
+     * @return the text in the previous position
+     */
+    public String yankPop() {
+        lastKill = false;
+        if (lastYank) {
+            prev();
+            return slots[head];
+        }
+        return null;
+    }
+
+    /**
+     * Moves the pointer to the current slot forward. If the end of
+     * the slots is reached then points back to the beginning.
+     */
+    private void next() {
+        if (head == 0 && slots[0] == null) {
+            return;
+        }
+        head++;
+        if (head == slots.length) {
+            head = 0;
+        }
+    }
+
+    /**
+     * Moves the pointer to the current slot backwards. If the
+     * beginning of the slots is reached then traverses the slot
+     * backwards until one with not null content is found.
+     */
+    private void prev() {
+        head--;
+        if (head == -1) {
+            int x = (slots.length - 1);
+            for (; x >= 0; x--) {
+                if (slots[x] != null) {
+                    break;
+                }
+            }
+            head = x;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,5683 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import java.io.Flushable;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.time.Instant;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.org.jline.keymap.BindingReader;
+import jdk.internal.org.jline.keymap.KeyMap;
+import jdk.internal.org.jline.reader.*;
+import jdk.internal.org.jline.reader.Parser.ParseContext;
+import jdk.internal.org.jline.reader.impl.history.DefaultHistory;
+import jdk.internal.org.jline.terminal.*;
+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.utils.AttributedString;
+import jdk.internal.org.jline.utils.AttributedStringBuilder;
+import jdk.internal.org.jline.utils.AttributedStyle;
+import jdk.internal.org.jline.utils.Curses;
+import jdk.internal.org.jline.utils.Display;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+import jdk.internal.org.jline.utils.Levenshtein;
+import jdk.internal.org.jline.utils.Log;
+import jdk.internal.org.jline.utils.Status;
+import jdk.internal.org.jline.utils.WCWidth;
+
+import static jdk.internal.org.jline.keymap.KeyMap.alt;
+import static jdk.internal.org.jline.keymap.KeyMap.ctrl;
+import static jdk.internal.org.jline.keymap.KeyMap.del;
+import static jdk.internal.org.jline.keymap.KeyMap.esc;
+import static jdk.internal.org.jline.keymap.KeyMap.range;
+import static jdk.internal.org.jline.keymap.KeyMap.translate;
+
+/**
+ * A reader for terminal applications. It supports custom tab-completion,
+ * saveable command history, and command line editing.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+@SuppressWarnings("StatementWithEmptyBody")
+public class LineReaderImpl implements LineReader, Flushable
+{
+    public static final char NULL_MASK = 0;
+
+    public static final int TAB_WIDTH = 4;
+
+
+    public static final String DEFAULT_WORDCHARS = "*?_-.[]~=/&;!#$%^(){}<>";
+    public static final String DEFAULT_REMOVE_SUFFIX_CHARS = " \t\n;&|";
+    public static final String DEFAULT_COMMENT_BEGIN = "#";
+    public static final String DEFAULT_SEARCH_TERMINATORS = "\033\012";
+    public static final String DEFAULT_BELL_STYLE = "";
+    public static final int    DEFAULT_LIST_MAX = 100;
+    public static final int    DEFAULT_ERRORS = 2;
+    public static final long   DEFAULT_BLINK_MATCHING_PAREN = 500L;
+    public static final long   DEFAULT_AMBIGUOUS_BINDING = 1000L;
+    public static final String DEFAULT_SECONDARY_PROMPT_PATTERN = "%M> ";
+    public static final String DEFAULT_OTHERS_GROUP_NAME = "others";
+    public static final String DEFAULT_ORIGINAL_GROUP_NAME = "original";
+    public static final String DEFAULT_COMPLETION_STYLE_STARTING = "36";    // cyan
+    public static final String DEFAULT_COMPLETION_STYLE_DESCRIPTION = "90"; // dark gray
+    public static final String DEFAULT_COMPLETION_STYLE_GROUP = "35;1";     // magenta
+    public static final String DEFAULT_COMPLETION_STYLE_SELECTION = "7";    // inverted
+
+    private static final int MIN_ROWS = 3;
+
+    public static final String BRACKETED_PASTE_ON = "\033[?2004h";
+    public static final String BRACKETED_PASTE_OFF = "\033[?2004l";
+    public static final String BRACKETED_PASTE_BEGIN = "\033[200~";
+    public static final String BRACKETED_PASTE_END = "\033[201~";
+
+    public static final String FOCUS_IN_SEQ = "\033[I";
+    public static final String FOCUS_OUT_SEQ = "\033[O";
+
+    /**
+     * Possible states in which the current readline operation may be in.
+     */
+    protected enum State {
+        /**
+         * The user is just typing away
+         */
+        NORMAL,
+        /**
+         * readLine should exit and return the buffer content
+         */
+        DONE,
+        /**
+         * readLine should exit and throw an EOFException
+         */
+        EOF,
+        /**
+         * readLine should exit and throw an UserInterruptException
+         */
+        INTERRUPT
+    }
+
+    protected enum ViMoveMode {
+        NORMAL,
+        YANK,
+        DELETE,
+        CHANGE
+    }
+
+    protected enum BellType {
+        NONE,
+        AUDIBLE,
+        VISIBLE
+    }
+
+    //
+    // Constructor variables
+    //
+
+    /** The terminal to use */
+    protected final Terminal terminal;
+    /** The application name */
+    protected final String appName;
+    /** The terminal keys mapping */
+    protected final Map<String, KeyMap<Binding>> keyMaps;
+
+    //
+    // Configuration
+    //
+    protected final Map<String, Object> variables;
+    protected History history = new DefaultHistory();
+    protected Completer completer = null;
+    protected Highlighter highlighter = new DefaultHighlighter();
+    protected Parser parser = new DefaultParser();
+    protected Expander expander = new DefaultExpander();
+
+    //
+    // State variables
+    //
+
+    protected final Map<Option, Boolean> options = new HashMap<>();
+
+    protected final Buffer buf = new BufferImpl();
+
+    protected final Size size = new Size();
+
+    protected AttributedString prompt;
+    protected AttributedString rightPrompt;
+
+    protected MaskingCallback maskingCallback;
+
+    protected Map<Integer, String> modifiedHistory = new HashMap<>();
+    protected Buffer historyBuffer = null;
+    protected CharSequence searchBuffer;
+    protected StringBuffer searchTerm = null;
+    protected boolean searchFailing;
+    protected boolean searchBackward;
+    protected int searchIndex = -1;
+
+
+    // Reading buffers
+    protected final BindingReader bindingReader;
+
+
+    /**
+     * VI character find
+     */
+    protected int findChar;
+    protected int findDir;
+    protected int findTailAdd;
+    /**
+     * VI history string search
+     */
+    private int searchDir;
+    private String searchString;
+
+    /**
+     * Region state
+     */
+    protected int regionMark;
+    protected RegionType regionActive;
+
+    private boolean forceChar;
+    private boolean forceLine;
+
+    /**
+     * The vi yank buffer
+     */
+    protected String yankBuffer = "";
+
+    protected ViMoveMode viMoveMode = ViMoveMode.NORMAL;
+
+    protected KillRing killRing = new KillRing();
+
+    protected UndoTree<Buffer> undo = new UndoTree<>(this::setBuffer);
+    protected boolean isUndo;
+
+    /*
+     * Current internal state of the line reader
+     */
+    protected State   state = State.DONE;
+    protected final AtomicBoolean startedReading = new AtomicBoolean();
+    protected boolean reading;
+
+    protected Supplier<AttributedString> post;
+
+    protected Map<String, Widget> builtinWidgets;
+    protected Map<String, Widget> widgets;
+
+    protected int count;
+    protected int mult;
+    protected int universal = 4;
+    protected int repeatCount;
+    protected boolean isArgDigit;
+
+    protected ParsedLine parsedLine;
+
+    protected boolean skipRedisplay;
+    protected Display display;
+
+    protected boolean overTyping = false;
+
+    protected String keyMap;
+
+    protected int smallTerminalOffset = 0;
+
+
+
+    public LineReaderImpl(Terminal terminal) throws IOException {
+        this(terminal, null, null);
+    }
+
+    public LineReaderImpl(Terminal terminal, String appName) throws IOException {
+        this(terminal, appName, null);
+    }
+
+    public LineReaderImpl(Terminal terminal, String appName, Map<String, Object> variables) {
+        Objects.requireNonNull(terminal, "terminal can not be null");
+        this.terminal = terminal;
+        if (appName == null) {
+            appName = "JLine";
+        }
+        this.appName = appName;
+        if (variables != null) {
+            this.variables = variables;
+        } else {
+            this.variables = new HashMap<>();
+        }
+        this.keyMaps = defaultKeyMaps();
+
+        builtinWidgets = builtinWidgets();
+        widgets = new HashMap<>(builtinWidgets);
+        bindingReader = new BindingReader(terminal.reader());
+    }
+
+    public Terminal getTerminal() {
+        return terminal;
+    }
+
+    public String getAppName() {
+        return appName;
+    }
+
+    public Map<String, KeyMap<Binding>> getKeyMaps() {
+        return keyMaps;
+    }
+
+    public KeyMap<Binding> getKeys() {
+        return keyMaps.get(keyMap);
+    }
+
+    @Override
+    public Map<String, Widget> getWidgets() {
+        return widgets;
+    }
+
+    @Override
+    public Map<String, Widget> getBuiltinWidgets() {
+        return Collections.unmodifiableMap(builtinWidgets);
+    }
+
+    @Override
+    public Buffer getBuffer() {
+        return buf;
+    }
+
+    @Override
+    public void runMacro(String macro) {
+        bindingReader.runMacro(macro);
+    }
+
+    @Override
+    public MouseEvent readMouseEvent() {
+        return terminal.readMouseEvent(bindingReader::readCharacter);
+    }
+
+    /**
+     * Set the completer.
+     *
+     * @param completer the completer to use
+     */
+    public void setCompleter(Completer completer) {
+        this.completer = completer;
+    }
+
+    /**
+     * Returns the completer.
+     *
+     * @return the completer
+     */
+    public Completer getCompleter() {
+        return completer;
+    }
+
+    //
+    // History
+    //
+
+    public void setHistory(final History history) {
+        Objects.requireNonNull(history);
+        this.history = history;
+    }
+
+    public History getHistory() {
+        return history;
+    }
+
+    //
+    // Highlighter
+    //
+
+    public void setHighlighter(Highlighter highlighter) {
+        this.highlighter = highlighter;
+    }
+
+    public Highlighter getHighlighter() {
+        return highlighter;
+    }
+
+    public Parser getParser() {
+        return parser;
+    }
+
+    public void setParser(Parser parser) {
+        this.parser = parser;
+    }
+
+    @Override
+    public Expander getExpander() {
+        return expander;
+    }
+
+    public void setExpander(Expander expander) {
+        this.expander = expander;
+    }
+
+    //
+    // Line Reading
+    //
+
+    /**
+     * Read the next line and return the contents of the buffer.
+     *
+     * @return          A line that is read from the terminal, can never be null.
+     */
+    public String readLine() throws UserInterruptException, EndOfFileException {
+        return readLine(null, null, (MaskingCallback) null, null);
+    }
+
+    /**
+     * Read the next line with the specified character mask. If null, then
+     * characters will be echoed. If 0, then no characters will be echoed.
+     *
+     * @param mask      The mask character, <code>null</code> or <code>0</code>.
+     * @return          A line that is read from the terminal, can never be null.
+     */
+    public String readLine(Character mask) throws UserInterruptException, EndOfFileException {
+        return readLine(null, null, mask, null);
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     * @return          A line that is read from the terminal, can never be null.
+     */
+    public String readLine(String prompt) throws UserInterruptException, EndOfFileException {
+        return readLine(prompt, null, (MaskingCallback) null, null);
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     * @param mask      The mask character, <code>null</code> or <code>0</code>.
+     * @return          A line that is read from the terminal, can never be null.
+     */
+    public String readLine(String prompt, Character mask) throws UserInterruptException, EndOfFileException {
+        return readLine(prompt, null, mask, null);
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt    The prompt to issue to the terminal, may be null.
+     * @param mask      The mask character, <code>null</code> or <code>0</code>.
+     * @param buffer    A string that will be set for editing.
+     * @return          A line that is read from the terminal, can never be null.
+     */
+    public String readLine(String prompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException {
+        return readLine(prompt, null, mask, buffer);
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt      The prompt to issue to the terminal, may be null.
+     * @param rightPrompt The prompt to issue to the right of the terminal, may be null.
+     * @param mask        The mask character, <code>null</code> or <code>0</code>.
+     * @param buffer      A string that will be set for editing.
+     * @return            A line that is read from the terminal, can never be null.
+     */
+    public String readLine(String prompt, String rightPrompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException {
+        return readLine(prompt, rightPrompt, mask != null ? new SimpleMaskingCallback(mask) : null, buffer);
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt          The prompt to issue to the terminal, may be null.
+     * @param rightPrompt     The prompt to issue to the right of the terminal, may be null.
+     * @param maskingCallback The callback used to mask parts of the edited line.
+     * @param buffer          A string that will be set for editing.
+     * @return                A line that is read from the terminal, can never be null.
+     */
+    public String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer) throws UserInterruptException, EndOfFileException {
+        // prompt may be null
+        // maskingCallback may be null
+        // buffer may be null
+
+        if (!startedReading.compareAndSet(false, true)) {
+            throw new IllegalStateException();
+        }
+
+        Thread readLineThread = Thread.currentThread();
+        SignalHandler previousIntrHandler = null;
+        SignalHandler previousWinchHandler = null;
+        SignalHandler previousContHandler = null;
+        Attributes originalAttributes = null;
+        boolean dumb = Terminal.TYPE_DUMB.equals(terminal.getType())
+                    || Terminal.TYPE_DUMB_COLOR.equals(terminal.getType());
+        try {
+
+            this.maskingCallback = maskingCallback;
+
+            /*
+             * This is the accumulator for VI-mode repeat count. That is, while in
+             * move mode, if you type 30x it will delete 30 characters. This is
+             * where the "30" is accumulated until the command is struck.
+             */
+            repeatCount = 0;
+            mult = 1;
+            regionActive = RegionType.NONE;
+            regionMark = -1;
+
+            smallTerminalOffset = 0;
+
+            state = State.NORMAL;
+
+            modifiedHistory.clear();
+
+            setPrompt(prompt);
+            setRightPrompt(rightPrompt);
+            buf.clear();
+            if (buffer != null) {
+                buf.write(buffer);
+            }
+            undo.clear();
+            parsedLine = null;
+            keyMap = MAIN;
+
+            if (history != null) {
+                history.attach(this);
+            }
+
+            synchronized (this) {
+                this.reading = true;
+
+                previousIntrHandler = terminal.handle(Signal.INT, signal -> readLineThread.interrupt());
+                previousWinchHandler = terminal.handle(Signal.WINCH, this::handleSignal);
+                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);
+
+                // Move into application mode
+                if (!dumb) {
+                    terminal.puts(Capability.keypad_xmit);
+                    if (isSet(Option.AUTO_FRESH_LINE))
+                        callWidget(FRESH_LINE);
+                    if (isSet(Option.MOUSE))
+                        terminal.trackMouse(Terminal.MouseTracking.Normal);
+                    if (isSet(Option.BRACKETED_PASTE))
+                        terminal.writer().write(BRACKETED_PASTE_ON);
+                } else {
+                    // For dumb terminals, we need to make sure that CR are ignored
+                    Attributes attr = new Attributes(originalAttributes);
+                    attr.setInputFlag(Attributes.InputFlag.IGNCR, true);
+                    terminal.setAttributes(attr);
+                }
+
+                callWidget(CALLBACK_INIT);
+
+                undo.newState(buf.copy());
+
+                // Draw initial prompt
+                redrawLine();
+                redisplay();
+            }
+
+            while (true) {
+
+                KeyMap<Binding> local = null;
+                if (isInViCmdMode() && regionActive != RegionType.NONE) {
+                    local = keyMaps.get(VISUAL);
+                }
+                Binding o = readBinding(getKeys(), local);
+                if (o == null) {
+                    throw new EndOfFileException();
+                }
+                Log.trace("Binding: ", o);
+                if (buf.length() == 0 && getLastBinding().charAt(0) == originalAttributes.getControlChar(ControlChar.VEOF)) {
+                    throw new EndOfFileException();
+                }
+
+                // If this is still false after handling the binding, then
+                // we reset our repeatCount to 0.
+                isArgDigit = false;
+                // Every command that can be repeated a specified number
+                // of times, needs to know how many times to repeat, so
+                // we figure that out here.
+                count = ((repeatCount == 0) ? 1 : repeatCount) * mult;
+                // Reset undo/redo flag
+                isUndo = false;
+                // Reset region after a paste
+                if (regionActive == RegionType.PASTE) {
+                    regionActive = RegionType.NONE;
+                }
+
+                synchronized (this) {
+                    // Get executable widget
+                    Buffer copy = buf.copy();
+                    Widget w = getWidget(o);
+                    if (!w.apply()) {
+                        beep();
+                    }
+                    if (!isUndo && !copy.toString().equals(buf.toString())) {
+                        undo.newState(buf.copy());
+                    }
+
+                    switch (state) {
+                        case DONE:
+                            return finishBuffer();
+                        case EOF:
+                            throw new EndOfFileException();
+                        case INTERRUPT:
+                            throw new UserInterruptException(buf.toString());
+                    }
+
+                    if (!isArgDigit) {
+                        /*
+                         * If the operation performed wasn't a vi argument
+                         * digit, then clear out the current repeatCount;
+                         */
+                        repeatCount = 0;
+                        mult = 1;
+                    }
+
+                    if (!dumb) {
+                        redisplay();
+                    }
+                }
+            }
+        } catch (IOError e) {
+            if (e.getCause() instanceof InterruptedIOException) {
+                throw new UserInterruptException(buf.toString());
+            } else {
+                throw e;
+            }
+        }
+        finally {
+            synchronized (this) {
+                this.reading = false;
+
+                cleanup();
+                if (originalAttributes != null) {
+                    terminal.setAttributes(originalAttributes);
+                }
+                if (previousIntrHandler != null) {
+                    terminal.handle(Signal.INT, previousIntrHandler);
+                }
+                if (previousWinchHandler != null) {
+                    terminal.handle(Signal.WINCH, previousWinchHandler);
+                }
+                if (previousContHandler != null) {
+                    terminal.handle(Signal.CONT, previousContHandler);
+                }
+            }
+            startedReading.set(false);
+        }
+    }
+
+    @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();
+    }
+
+    @Override
+    public void printAbove(AttributedString str) {
+        printAbove(str.toAnsi(terminal));
+    }
+
+    @Override
+    public synchronized boolean isReading() {
+        return reading;
+    }
+
+    /* Make sure we position the cursor on column 0 */
+    protected boolean freshLine() {
+        boolean wrapAtEol = terminal.getBooleanCapability(Capability.auto_right_margin);
+        boolean delayedWrapAtEol = wrapAtEol && terminal.getBooleanCapability(Capability.eat_newline_glitch);
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        sb.style(AttributedStyle.DEFAULT.foreground(AttributedStyle.BLACK + AttributedStyle.BRIGHT));
+        sb.append("~");
+        sb.style(AttributedStyle.DEFAULT);
+        if (!wrapAtEol || delayedWrapAtEol) {
+            for (int i = 0; i < size.getColumns() - 1; i++) {
+                sb.append(" ");
+            }
+            sb.append(KeyMap.key(terminal, Capability.carriage_return));
+            sb.append(" ");
+            sb.append(KeyMap.key(terminal, Capability.carriage_return));
+        } else {
+            // Given the terminal will wrap automatically,
+            // we need to print one less than needed.
+            // This means that the last character will not
+            // be overwritten, and that's why we're using
+            // a clr_eol first if possible.
+            String el = terminal.getStringCapability(Capability.clr_eol);
+            if (el != null) {
+                Curses.tputs(sb, el);
+            }
+            for (int i = 0; i < size.getColumns() - 2; i++) {
+                sb.append(" ");
+            }
+            sb.append(KeyMap.key(terminal, Capability.carriage_return));
+            sb.append(" ");
+            sb.append(KeyMap.key(terminal, Capability.carriage_return));
+        }
+        print(sb.toAnsi(terminal));
+        return true;
+    }
+
+    @Override
+    public synchronized void callWidget(String name) {
+        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);
+        }
+    }
+
+    /**
+     * Clear the line and redraw it.
+     * @return <code>true</code>
+     */
+    public boolean redrawLine() {
+        display.reset();
+        return true;
+    }
+
+    /**
+     * Write out the specified string to the buffer and the output stream.
+     * @param str the char sequence to write in the buffer
+     */
+    public void putString(final CharSequence str) {
+        buf.write(str, overTyping);
+    }
+
+    /**
+     * Flush the terminal output stream. This is important for printout out single
+     * characters (like a buf.backspace or keyboard) that we want the terminal to
+     * handle immediately.
+     */
+    public void flush() {
+        terminal.flush();
+    }
+
+    public boolean isKeyMap(String name) {
+        return keyMap.equals(name);
+    }
+
+    /**
+     * Read a character from the terminal.
+     *
+     * @return the character, or -1 if an EOF is received.
+     */
+    public int readCharacter() {
+        return bindingReader.readCharacter();
+    }
+
+    public int peekCharacter(long timeout) {
+        return bindingReader.peekCharacter(timeout);
+    }
+
+    /**
+     * Read from the input stream and decode an operation from the key map.
+     *
+     * The input stream will be read character by character until a matching
+     * binding can be found.  Characters that can't possibly be matched to
+     * any binding will be discarded.
+     *
+     * @param keys the KeyMap to use for decoding the input stream
+     * @return the decoded binding or <code>null</code> if the end of
+     *         stream has been reached
+     */
+    public Binding readBinding(KeyMap<Binding> keys) {
+        return readBinding(keys, null);
+    }
+
+    public Binding readBinding(KeyMap<Binding> keys, KeyMap<Binding> local) {
+        Binding o = bindingReader.readBinding(keys, local);
+        /*
+         * The kill ring keeps record of whether or not the
+         * previous command was a yank or a kill. We reset
+         * that state here if needed.
+         */
+        if (o instanceof Reference) {
+            String ref = ((Reference) o).name();
+            if (!YANK_POP.equals(ref) && !YANK.equals(ref)) {
+                killRing.resetLastYank();
+            }
+            if (!KILL_LINE.equals(ref) && !KILL_WHOLE_LINE.equals(ref)
+                    && !BACKWARD_KILL_WORD.equals(ref) && !KILL_WORD.equals(ref)) {
+                killRing.resetLastKill();
+            }
+        }
+        return o;
+    }
+
+    @Override
+    public ParsedLine getParsedLine() {
+        return parsedLine;
+    }
+
+    public String getLastBinding() {
+        return bindingReader.getLastBinding();
+    }
+
+    public String getSearchTerm() {
+        return searchTerm != null ? searchTerm.toString() : null;
+    }
+
+    @Override
+    public RegionType getRegionActive() {
+        return regionActive;
+    }
+
+    @Override
+    public int getRegionMark() {
+        return regionMark;
+    }
+
+    //
+    // Key Bindings
+    //
+
+    /**
+     * Sets the current keymap by name. Supported keymaps are "emacs",
+     * "viins", "vicmd".
+     * @param name The name of the keymap to switch to
+     * @return true if the keymap was set, or false if the keymap is
+     *    not recognized.
+     */
+    public boolean setKeyMap(String name) {
+        KeyMap<Binding> map = keyMaps.get(name);
+        if (map == null) {
+            return false;
+        }
+        this.keyMap = name;
+        if (reading) {
+            callWidget(CALLBACK_KEYMAP);
+        }
+        return true;
+    }
+
+    /**
+     * Returns the name of the current key mapping.
+     * @return the name of the key mapping. This will be the canonical name
+     *   of the current mode of the key map and may not reflect the name that
+     *   was used with {@link #setKeyMap(String)}.
+     */
+    public String getKeyMap() {
+        return keyMap;
+    }
+
+    @Override
+    public LineReader variable(String name, Object value) {
+        variables.put(name, value);
+        return this;
+    }
+
+    @Override
+    public Map<String, Object> getVariables() {
+        return variables;
+    }
+
+    @Override
+    public Object getVariable(String name) {
+        return variables.get(name);
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        variables.put(name, value);
+    }
+
+    @Override
+    public LineReader option(Option option, boolean value) {
+        options.put(option, value);
+        return this;
+    }
+
+    @Override
+    public boolean isSet(Option option) {
+        Boolean b = options.get(option);
+        return b != null ? b : option.isDef();
+    }
+
+    @Override
+    public void setOpt(Option option) {
+        options.put(option, Boolean.TRUE);
+    }
+
+    @Override
+    public void unsetOpt(Option option) {
+        options.put(option, Boolean.FALSE);
+    }
+
+
+
+    //
+    // Widget implementation
+    //
+
+    /**
+     * Clear the buffer and add its contents to the history.
+     *
+     * @return the former contents of the buffer.
+     */
+    protected String finishBuffer() {
+        String str = buf.toString();
+        String historyLine = str;
+
+        if (!isSet(Option.DISABLE_EVENT_EXPANSION)) {
+            StringBuilder sb = new StringBuilder();
+            boolean escaped = false;
+            for (int i = 0; i < str.length(); i++) {
+                char ch = str.charAt(i);
+                if (escaped) {
+                    escaped = false;
+                    if (ch != '\n') {
+                        sb.append(ch);
+                    }
+                } else if (ch == '\\') {
+                    escaped = true;
+                } else {
+                    sb.append(ch);
+                }
+            }
+            str = sb.toString();
+        }
+
+        if (maskingCallback != null) {
+            historyLine = maskingCallback.history(historyLine);
+        }
+
+        // we only add it to the history if the buffer is not empty
+        if (historyLine != null && historyLine.length() > 0 ) {
+            history.add(Instant.now(), historyLine);
+        }
+        return str;
+    }
+
+    protected void handleSignal(Signal signal) {
+        if (signal == Signal.WINCH) {
+            size.copy(terminal.getSize());
+            display.resize(size.getRows(), size.getColumns());
+            redisplay();
+        }
+        else if (signal == Signal.CONT) {
+            terminal.enterRawMode();
+            size.copy(terminal.getSize());
+            display.resize(size.getRows(), size.getColumns());
+            terminal.puts(Capability.keypad_xmit);
+            redrawLine();
+            redisplay();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Widget getWidget(Object binding) {
+        Widget w;
+        if (binding instanceof Widget) {
+            w = (Widget) binding;
+        } else if (binding instanceof Macro) {
+            String macro = ((Macro) binding).getSequence();
+            w = () -> {
+                bindingReader.runMacro(macro);
+                return true;
+            };
+        } else if (binding instanceof Reference) {
+            String name = ((Reference) binding).name();
+            w = widgets.get(name);
+            if (w == null) {
+                w = () -> {
+                    post = () -> new AttributedString("No such widget `" + name + "'");
+                    return false;
+                };
+            }
+        } else {
+            w = () -> {
+                post = () -> new AttributedString("Unsupported widget");
+                return false;
+            };
+        }
+        return w;
+    }
+
+    //
+    // Helper methods
+    //
+
+    public void setPrompt(final String prompt) {
+        this.prompt = (prompt == null ? AttributedString.EMPTY
+                       : expandPromptPattern(prompt, 0, "", 0));
+    }
+
+    public void setRightPrompt(final String rightPrompt) {
+        this.rightPrompt = (rightPrompt == null ? AttributedString.EMPTY
+                            : expandPromptPattern(rightPrompt, 0, "", 0));
+    }
+
+    protected void setBuffer(Buffer buffer) {
+        buf.copyFrom(buffer);
+    }
+
+    /**
+     * Set the current buffer's content to the specified {@link String}. The
+     * visual terminal will be modified to show the current buffer.
+     *
+     * @param buffer the new contents of the buffer.
+     */
+    protected void setBuffer(final String buffer) {
+        buf.clear();
+        buf.write(buffer);
+    }
+
+    /**
+     * This method is calling while doing a delete-to ("d"), change-to ("c"),
+     * or yank-to ("y") and it filters out only those movement operations
+     * that are allowable during those operations. Any operation that isn't
+     * allow drops you back into movement mode.
+     *
+     * @param op The incoming operation to remap
+     * @return The remaped operation
+     */
+    protected String viDeleteChangeYankToRemap (String op) {
+        switch (op) {
+            case SEND_BREAK:
+            case BACKWARD_CHAR:
+            case FORWARD_CHAR:
+            case END_OF_LINE:
+            case VI_MATCH_BRACKET:
+            case VI_DIGIT_OR_BEGINNING_OF_LINE:
+            case NEG_ARGUMENT:
+            case DIGIT_ARGUMENT:
+            case VI_BACKWARD_CHAR:
+            case VI_BACKWARD_WORD:
+            case VI_FORWARD_CHAR:
+            case VI_FORWARD_WORD:
+            case VI_FORWARD_WORD_END:
+            case VI_FIRST_NON_BLANK:
+            case VI_GOTO_COLUMN:
+            case VI_DELETE:
+            case VI_YANK:
+            case VI_CHANGE:
+            case VI_FIND_NEXT_CHAR:
+            case VI_FIND_NEXT_CHAR_SKIP:
+            case VI_FIND_PREV_CHAR:
+            case VI_FIND_PREV_CHAR_SKIP:
+            case VI_REPEAT_FIND:
+            case VI_REV_REPEAT_FIND:
+                return op;
+
+            default:
+                return VI_CMD_MODE;
+        }
+    }
+
+    protected int switchCase(int ch) {
+        if (Character.isUpperCase(ch)) {
+            return Character.toLowerCase(ch);
+        } else if (Character.isLowerCase(ch)) {
+            return Character.toUpperCase(ch);
+        } else {
+            return ch;
+        }
+    }
+
+    /**
+     * @return true if line reader is in the middle of doing a change-to
+     *   delete-to or yank-to.
+     */
+    protected boolean isInViMoveOperation() {
+        return viMoveMode != ViMoveMode.NORMAL;
+    }
+
+    protected boolean isInViChangeOperation() {
+        return viMoveMode == ViMoveMode.CHANGE;
+    }
+
+    protected boolean isInViCmdMode() {
+        return VICMD.equals(keyMap);
+    }
+
+
+    //
+    // Movement
+    //
+
+    protected boolean viForwardChar() {
+        if (count < 0) {
+            return callNeg(this::viBackwardChar);
+        }
+        int lim = findeol();
+        if (isInViCmdMode() && !isInViMoveOperation()) {
+            lim--;
+        }
+        if (buf.cursor() >= lim) {
+            return false;
+        }
+        while (count-- > 0 && buf.cursor() < lim) {
+            buf.move(1);
+        }
+        return true;
+    }
+
+    protected boolean viBackwardChar() {
+        if (count < 0) {
+            return callNeg(this::viForwardChar);
+        }
+        int lim = findbol();
+        if (buf.cursor() == lim) {
+            return false;
+        }
+        while (count-- > 0 && buf.cursor() > 0) {
+            buf.move(-1);
+            if (buf.currChar() == '\n') {
+                buf.move(1);
+                break;
+            }
+        }
+        return true;
+    }
+
+
+    //
+    // Word movement
+    //
+
+    protected boolean forwardWord() {
+        if (count < 0) {
+            return callNeg(this::backwardWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length() && isWord(buf.currChar())) {
+                buf.move(1);
+            }
+            if (isInViChangeOperation() && count == 0) {
+                break;
+            }
+            while (buf.cursor() < buf.length() && !isWord(buf.currChar())) {
+                buf.move(1);
+            }
+        }
+        return true;
+    }
+
+    protected boolean viForwardWord() {
+        if (count < 0) {
+            return callNeg(this::backwardWord);
+        }
+        while (count-- > 0) {
+            if (isViAlphaNum(buf.currChar())) {
+                while (buf.cursor() < buf.length() && isViAlphaNum(buf.currChar())) {
+                    buf.move(1);
+                }
+            } else {
+                while (buf.cursor() < buf.length()
+                        && !isViAlphaNum(buf.currChar())
+                        && !isWhitespace(buf.currChar())) {
+                    buf.move(1);
+                }
+            }
+            if (isInViChangeOperation() && count == 0) {
+                return true;
+            }
+            int nl = buf.currChar() == '\n' ? 1 : 0;
+            while (buf.cursor() < buf.length()
+                    && nl < 2
+                    && isWhitespace(buf.currChar())) {
+                buf.move(1);
+                nl += buf.currChar() == '\n' ? 1 : 0;
+            }
+        }
+        return true;
+    }
+
+    protected boolean viForwardBlankWord() {
+        if (count < 0) {
+            return callNeg(this::viBackwardBlankWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length() && !isWhitespace(buf.currChar())) {
+                buf.move(1);
+            }
+            if (isInViChangeOperation() && count == 0) {
+                return true;
+            }
+            int nl = buf.currChar() == '\n' ? 1 : 0;
+            while (buf.cursor() < buf.length()
+                    && nl < 2
+                    && isWhitespace(buf.currChar())) {
+                buf.move(1);
+                nl += buf.currChar() == '\n' ? 1 : 0;
+            }
+        }
+        return true;
+    }
+
+    protected boolean emacsForwardWord() {
+        if (count < 0) {
+            return callNeg(this::emacsBackwardWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length() && !isWord(buf.currChar())) {
+                buf.move(1);
+            }
+            if (isInViChangeOperation() && count == 0) {
+                return true;
+            }
+            while (buf.cursor() < buf.length() && isWord(buf.currChar())) {
+                buf.move(1);
+            }
+        }
+        return true;
+    }
+
+    protected boolean viForwardBlankWordEnd() {
+        if (count < 0) {
+            return false;
+        }
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length()) {
+                buf.move(1);
+                if (!isWhitespace(buf.currChar())) {
+                    break;
+                }
+            }
+            while (buf.cursor() < buf.length()) {
+                buf.move(1);
+                if (isWhitespace(buf.currChar())) {
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected boolean viForwardWordEnd() {
+        if (count < 0) {
+            return callNeg(this::backwardWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length()) {
+                if (!isWhitespace(buf.nextChar())) {
+                    break;
+                }
+                buf.move(1);
+            }
+            if (buf.cursor() < buf.length()) {
+                if (isViAlphaNum(buf.nextChar())) {
+                    buf.move(1);
+                    while (buf.cursor() < buf.length() && isViAlphaNum(buf.nextChar())) {
+                        buf.move(1);
+                    }
+                } else {
+                    buf.move(1);
+                    while (buf.cursor() < buf.length() && !isViAlphaNum(buf.nextChar()) && !isWhitespace(buf.nextChar())) {
+                        buf.move(1);
+                    }
+                }
+            }
+        }
+        if (buf.cursor() < buf.length() && isInViMoveOperation()) {
+            buf.move(1);
+        }
+        return true;
+    }
+
+    protected boolean backwardWord() {
+        if (count < 0) {
+            return callNeg(this::forwardWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() > 0 && !isWord(buf.atChar(buf.cursor() - 1))) {
+                buf.move(-1);
+            }
+            while (buf.cursor() > 0 && isWord(buf.atChar(buf.cursor() - 1))) {
+                buf.move(-1);
+            }
+        }
+        return true;
+    }
+
+    protected boolean viBackwardWord() {
+        if (count < 0) {
+            return callNeg(this::backwardWord);
+        }
+        while (count-- > 0) {
+            int nl = 0;
+            while (buf.cursor() > 0) {
+                buf.move(-1);
+                if (!isWhitespace(buf.currChar())) {
+                    break;
+                }
+                nl += buf.currChar() == '\n' ? 1 : 0;
+                if (nl == 2) {
+                    buf.move(1);
+                    break;
+                }
+            }
+            if (buf.cursor() > 0) {
+                if (isViAlphaNum(buf.currChar())) {
+                    while (buf.cursor() > 0) {
+                        if (!isViAlphaNum(buf.prevChar())) {
+                            break;
+                        }
+                        buf.move(-1);
+                    }
+                } else {
+                    while (buf.cursor() > 0) {
+                        if (isViAlphaNum(buf.prevChar()) || isWhitespace(buf.prevChar())) {
+                            break;
+                        }
+                        buf.move(-1);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    protected boolean viBackwardBlankWord() {
+        if (count < 0) {
+            return callNeg(this::viForwardBlankWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() > 0) {
+                buf.move(-1);
+                if (!isWhitespace(buf.currChar())) {
+                    break;
+                }
+            }
+            while (buf.cursor() > 0) {
+                buf.move(-1);
+                if (isWhitespace(buf.currChar())) {
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected boolean viBackwardWordEnd() {
+        if (count < 0) {
+            return callNeg(this::viForwardWordEnd);
+        }
+        while (count-- > 0 && buf.cursor() > 1) {
+            int start;
+            if (isViAlphaNum(buf.currChar())) {
+                start = 1;
+            } else if (!isWhitespace(buf.currChar())) {
+                start = 2;
+            } else {
+                start = 0;
+            }
+            while (buf.cursor() > 0) {
+                boolean same = (start != 1) && isWhitespace(buf.currChar());
+                if (start != 0) {
+                    same |= isViAlphaNum(buf.currChar());
+                }
+                if (same == (start == 2)) {
+                    break;
+                }
+                buf.move(-1);
+            }
+            while (buf.cursor() > 0 && isWhitespace(buf.currChar())) {
+                buf.move(-1);
+            }
+        }
+        return true;
+    }
+
+    protected boolean viBackwardBlankWordEnd() {
+        if (count < 0) {
+            return callNeg(this::viForwardBlankWordEnd);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() > 0 && !isWhitespace(buf.currChar())) {
+                buf.move(-1);
+            }
+            while (buf.cursor() > 0 && isWhitespace(buf.currChar())) {
+                buf.move(-1);
+            }
+        }
+        return true;
+    }
+
+    protected boolean emacsBackwardWord() {
+        if (count < 0) {
+            return callNeg(this::emacsForwardWord);
+        }
+        while (count-- > 0) {
+            while (buf.cursor() > 0) {
+                buf.move(-1);
+                if (isWord(buf.currChar())) {
+                    break;
+                }
+            }
+            while (buf.cursor() > 0) {
+                buf.move(-1);
+                if (!isWord(buf.currChar())) {
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    protected boolean backwardDeleteWord() {
+        if (count < 0) {
+            return callNeg(this::deleteWord);
+        }
+        int cursor = buf.cursor();
+        while (count-- > 0) {
+            while (cursor > 0 && !isWord(buf.atChar(cursor - 1))) {
+                cursor--;
+            }
+            while (cursor > 0 && isWord(buf.atChar(cursor - 1))) {
+                cursor--;
+            }
+        }
+        buf.backspace(buf.cursor() - cursor);
+        return true;
+    }
+
+    protected boolean viBackwardKillWord() {
+        if (count < 0) {
+            return false;
+        }
+        int lim = findbol();
+        int x = buf.cursor();
+        while (count-- > 0) {
+            while (x > lim && isWhitespace(buf.atChar(x - 1))) {
+                x--;
+            }
+            if (x > lim) {
+                if (isViAlphaNum(buf.atChar(x - 1))) {
+                    while (x > lim && isViAlphaNum(buf.atChar(x - 1))) {
+                        x--;
+                    }
+                } else {
+                    while (x > lim && !isViAlphaNum(buf.atChar(x - 1)) && !isWhitespace(buf.atChar(x - 1))) {
+                        x--;
+                    }
+                }
+            }
+        }
+        killRing.addBackwards(buf.substring(x, buf.cursor()));
+        buf.backspace(buf.cursor() - x);
+        return true;
+    }
+
+    protected boolean backwardKillWord() {
+        if (count < 0) {
+            return callNeg(this::killWord);
+        }
+        int x = buf.cursor();
+        while (count-- > 0) {
+            while (x > 0 && !isWord(buf.atChar(x - 1))) {
+                x--;
+            }
+            while (x > 0 && isWord(buf.atChar(x - 1))) {
+                x--;
+            }
+        }
+        killRing.addBackwards(buf.substring(x, buf.cursor()));
+        buf.backspace(buf.cursor() - x);
+        return true;
+    }
+
+    protected boolean copyPrevWord() {
+        if (count <= 0) {
+            return false;
+        }
+        int t1, t0 = buf.cursor();
+        while (true) {
+            t1 = t0;
+            while (t0 > 0 && !isWord(buf.atChar(t0 - 1))) {
+                t0--;
+            }
+            while (t0 > 0 && isWord(buf.atChar(t0 - 1))) {
+                t0--;
+            }
+            if (--count == 0) {
+                break;
+            }
+            if (t0 == 0) {
+                return false;
+            }
+        }
+        buf.write(buf.substring(t0, t1));
+        return true;
+    }
+
+    protected boolean upCaseWord() {
+        int count = Math.abs(this.count);
+        int cursor = buf.cursor();
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length() && !isWord(buf.currChar())) {
+                buf.move(1);
+            }
+            while (buf.cursor() < buf.length() && isWord(buf.currChar())) {
+                buf.currChar(Character.toUpperCase(buf.currChar()));
+                buf.move(1);
+            }
+        }
+        if (this.count < 0) {
+            buf.cursor(cursor);
+        }
+        return true;
+    }
+
+    protected boolean downCaseWord() {
+        int count = Math.abs(this.count);
+        int cursor = buf.cursor();
+        while (count-- > 0) {
+            while (buf.cursor() < buf.length() && !isWord(buf.currChar())) {
+                buf.move(1);
+            }
+            while (buf.cursor() < buf.length() && isWord(buf.currChar())) {
+                buf.currChar(Character.toLowerCase(buf.currChar()));
+                buf.move(1);
+            }
+        }
+        if (this.count < 0) {
+            buf.cursor(cursor);
+        }
+        return true;
+    }
+
+    protected boolean capitalizeWord() {
+        int count = Math.abs(this.count);
+        int cursor = buf.cursor();
+        while (count-- > 0) {
+            boolean first = true;
+            while (buf.cursor() < buf.length() && !isWord(buf.currChar())) {
+                buf.move(1);
+            }
+            while (buf.cursor() < buf.length() && isWord(buf.currChar()) && !isAlpha(buf.currChar())) {
+                buf.move(1);
+            }
+            while (buf.cursor() < buf.length() && isWord(buf.currChar())) {
+                buf.currChar(first
+                        ? Character.toUpperCase(buf.currChar())
+                        : Character.toLowerCase(buf.currChar()));
+                buf.move(1);
+                first = false;
+            }
+        }
+        if (this.count < 0) {
+            buf.cursor(cursor);
+        }
+        return true;
+    }
+
+    protected boolean deleteWord() {
+        if (count < 0) {
+            return callNeg(this::backwardDeleteWord);
+        }
+        int x = buf.cursor();
+        while (count-- > 0) {
+            while (x < buf.length() && !isWord(buf.atChar(x))) {
+                x++;
+            }
+            while (x < buf.length() && isWord(buf.atChar(x))) {
+                x++;
+            }
+        }
+        buf.delete(x - buf.cursor());
+        return true;
+    }
+
+    protected boolean killWord() {
+        if (count < 0) {
+            return callNeg(this::backwardKillWord);
+        }
+        int x = buf.cursor();
+        while (count-- > 0) {
+            while (x < buf.length() && !isWord(buf.atChar(x))) {
+                x++;
+            }
+            while (x < buf.length() && isWord(buf.atChar(x))) {
+                x++;
+            }
+        }
+        killRing.add(buf.substring(buf.cursor(), x));
+        buf.delete(x - buf.cursor());
+        return true;
+    }
+
+    protected boolean transposeWords() {
+        int lstart = buf.cursor() - 1;
+        int lend = buf.cursor();
+        while (buf.atChar(lstart) != 0 && buf.atChar(lstart) != '\n') {
+            lstart--;
+        }
+        lstart++;
+        while (buf.atChar(lend) != 0 && buf.atChar(lend) != '\n') {
+            lend++;
+        }
+        if (lend - lstart < 2) {
+            return false;
+        }
+        int words = 0;
+        boolean inWord = false;
+        if (!isDelimiter(buf.atChar(lstart))) {
+            words++;
+            inWord = true;
+        }
+        for (int i = lstart; i < lend; i++) {
+            if (isDelimiter(buf.atChar(i))) {
+                inWord = false;
+            } else {
+                if (!inWord) {
+                    words++;
+                }
+                inWord = true;
+            }
+        }
+        if (words < 2) {
+            return false;
+        }
+        // TODO: use isWord instead of isDelimiter
+        boolean neg = this.count < 0;
+        for (int count = Math.max(this.count, -this.count); count > 0; --count) {
+            int sta1, end1, sta2, end2;
+            // Compute current word boundaries
+            sta1 = buf.cursor();
+            while (sta1 > lstart && !isDelimiter(buf.atChar(sta1 - 1))) {
+                sta1--;
+            }
+            end1 = sta1;
+            while (end1 < lend && !isDelimiter(buf.atChar(++end1)));
+            if (neg) {
+                end2 = sta1 - 1;
+                while (end2 > lstart && isDelimiter(buf.atChar(end2 - 1))) {
+                    end2--;
+                }
+                if (end2 < lstart) {
+                    // No word before, use the word after
+                    sta2 = end1;
+                    while (isDelimiter(buf.atChar(++sta2)));
+                    end2 = sta2;
+                    while (end2 < lend && !isDelimiter(buf.atChar(++end2)));
+                } else {
+                    sta2 = end2;
+                    while (sta2 > lstart && !isDelimiter(buf.atChar(sta2 - 1))) {
+                        sta2--;
+                    }
+                }
+            } else {
+                sta2 = end1;
+                while (sta2 < lend && isDelimiter(buf.atChar(++sta2)));
+                if (sta2 == lend) {
+                    // No word after, use the word before
+                    end2 = sta1;
+                    while (isDelimiter(buf.atChar(end2 - 1))) {
+                        end2--;
+                    }
+                    sta2 = end2;
+                    while (sta2 > lstart && !isDelimiter(buf.atChar(sta2 - 1))) {
+                        sta2--;
+                    }
+                } else {
+                    end2 = sta2;
+                    while (end2 < lend && !isDelimiter(buf.atChar(++end2))) ;
+                }
+            }
+            if (sta1 < sta2) {
+                String res = buf.substring(0, sta1) + buf.substring(sta2, end2)
+                        + buf.substring(end1, sta2) + buf.substring(sta1, end1)
+                        + buf.substring(end2);
+                buf.clear();
+                buf.write(res);
+                buf.cursor(neg ? end1 : end2);
+            } else {
+                String res = buf.substring(0, sta2) + buf.substring(sta1, end1)
+                        + buf.substring(end2, sta1) + buf.substring(sta2, end2)
+                        + buf.substring(end1);
+                buf.clear();
+                buf.write(res);
+                buf.cursor(neg ? end2 : end1);
+            }
+        }
+        return true;
+    }
+
+    private int findbol() {
+        int x = buf.cursor();
+        while (x > 0 && buf.atChar(x - 1) != '\n') {
+            x--;
+        }
+        return x;
+    }
+
+    private int findeol() {
+        int x = buf.cursor();
+        while (x < buf.length() && buf.atChar(x) != '\n') {
+            x++;
+        }
+        return x;
+    }
+
+    protected boolean insertComment() {
+        return doInsertComment(false);
+    }
+
+    protected boolean viInsertComment() {
+        return doInsertComment(true);
+    }
+
+    protected boolean doInsertComment(boolean isViMode) {
+        String comment = getString(COMMENT_BEGIN, DEFAULT_COMMENT_BEGIN);
+        beginningOfLine();
+        putString(comment);
+        if (isViMode) {
+            setKeyMap(VIINS);
+        }
+        return acceptLine();
+    }
+
+    protected boolean viFindNextChar() {
+        if ((findChar = vigetkey()) > 0) {
+            findDir = 1;
+            findTailAdd = 0;
+            return vifindchar(false);
+        }
+        return false;
+    }
+
+    protected boolean viFindPrevChar() {
+        if ((findChar = vigetkey()) > 0) {
+            findDir = -1;
+            findTailAdd = 0;
+            return vifindchar(false);
+        }
+        return false;
+    }
+
+    protected boolean viFindNextCharSkip() {
+        if ((findChar = vigetkey()) > 0) {
+            findDir = 1;
+            findTailAdd = -1;
+            return vifindchar(false);
+        }
+        return false;
+    }
+
+    protected boolean viFindPrevCharSkip() {
+        if ((findChar = vigetkey()) > 0) {
+            findDir = -1;
+            findTailAdd = 1;
+            return vifindchar(false);
+        }
+        return false;
+    }
+
+    protected boolean viRepeatFind() {
+        return vifindchar(true);
+    }
+
+    protected boolean viRevRepeatFind() {
+        if (count < 0) {
+            return callNeg(() -> vifindchar(true));
+        }
+        findTailAdd = -findTailAdd;
+        findDir = -findDir;
+        boolean ret = vifindchar(true);
+        findTailAdd = -findTailAdd;
+        findDir = -findDir;
+        return ret;
+    }
+
+    private int vigetkey() {
+        int ch = readCharacter();
+        KeyMap<Binding> km = keyMaps.get(MAIN);
+        if (km != null) {
+            Binding b = km.getBound(new String(Character.toChars(ch)));
+            if (b instanceof Reference) {
+                String func = ((Reference) b).name();
+                if (SEND_BREAK.equals(func)) {
+                    return -1;
+                }
+            }
+        }
+        return ch;
+    }
+
+    private boolean vifindchar(boolean repeat) {
+        if (findDir == 0) {
+            return false;
+        }
+        if (count < 0) {
+            return callNeg(this::viRevRepeatFind);
+        }
+        if (repeat && findTailAdd != 0) {
+            if (findDir > 0) {
+                if (buf.cursor() < buf.length() && buf.nextChar() == findChar) {
+                    buf.move(1);
+                }
+            } else {
+                if (buf.cursor() > 0 && buf.prevChar() == findChar) {
+                    buf.move(-1);
+                }
+            }
+        }
+        int cursor = buf.cursor();
+        while (count-- > 0) {
+            do {
+                buf.move(findDir);
+            } while (buf.cursor() > 0 && buf.cursor() < buf.length()
+                    && buf.currChar() != findChar
+                    && buf.currChar() != '\n');
+            if (buf.cursor() <= 0 || buf.cursor() >= buf.length()
+                    || buf.currChar() == '\n') {
+                buf.cursor(cursor);
+                return false;
+            }
+        }
+        if (findTailAdd != 0) {
+            buf.move(findTailAdd);
+        }
+        if (findDir == 1 && isInViMoveOperation()) {
+            buf.move(1);
+        }
+        return true;
+    }
+
+    private boolean callNeg(Widget widget) {
+        this.count = -this.count;
+        boolean ret = widget.apply();
+        this.count = -this.count;
+        return ret;
+    }
+
+    /**
+     * Implements vi search ("/" or "?").
+     *
+     * @return <code>true</code> if the search was successful
+     */
+    protected boolean viHistorySearchForward() {
+        searchDir = 1;
+        searchIndex = 0;
+        return getViSearchString() && viRepeatSearch();
+    }
+
+    protected boolean viHistorySearchBackward() {
+        searchDir = -1;
+        searchIndex = history.size() - 1;
+        return getViSearchString() && viRepeatSearch();
+    }
+
+    protected boolean viRepeatSearch() {
+        if (searchDir == 0) {
+            return false;
+        }
+        int si = searchDir < 0
+                ? searchBackwards(searchString, searchIndex, false)
+                : searchForwards(searchString, searchIndex, false);
+        if (si == -1 || si == history.index()) {
+            return false;
+        }
+        searchIndex = si;
+
+        /*
+         * Show the match.
+         */
+        buf.clear();
+        history.moveTo(searchIndex);
+        buf.write(history.get(searchIndex));
+        if (VICMD.equals(keyMap)) {
+            buf.move(-1);
+        }
+        return true;
+    }
+
+    protected boolean viRevRepeatSearch() {
+        boolean ret;
+        searchDir = -searchDir;
+        ret = viRepeatSearch();
+        searchDir = -searchDir;
+        return ret;
+    }
+
+    private boolean getViSearchString() {
+        if (searchDir == 0) {
+            return false;
+        }
+        String searchPrompt = searchDir < 0 ? "?" : "/";
+        Buffer searchBuffer = new BufferImpl();
+
+        KeyMap<Binding> keyMap = keyMaps.get(MAIN);
+        if (keyMap == null) {
+            keyMap = keyMaps.get(SAFE);
+        }
+        while (true) {
+            post = () -> new AttributedString(searchPrompt + searchBuffer.toString() + "_");
+            redisplay();
+            Binding b = bindingReader.readBinding(keyMap);
+            if (b instanceof Reference) {
+                String func = ((Reference) b).name();
+                switch (func) {
+                    case SEND_BREAK:
+                        post = null;
+                        return false;
+                    case ACCEPT_LINE:
+                    case VI_CMD_MODE:
+                        searchString = searchBuffer.toString();
+                        post = null;
+                        return true;
+                    case MAGIC_SPACE:
+                        searchBuffer.write(' ');
+                        break;
+                    case REDISPLAY:
+                        redisplay();
+                        break;
+                    case CLEAR_SCREEN:
+                        clearScreen();
+                        break;
+                    case SELF_INSERT:
+                        searchBuffer.write(getLastBinding());
+                        break;
+                    case SELF_INSERT_UNMETA:
+                        if (getLastBinding().charAt(0) == '\u001b') {
+                            String s = getLastBinding().substring(1);
+                            if ("\r".equals(s)) {
+                                s = "\n";
+                            }
+                            searchBuffer.write(s);
+                        }
+                        break;
+                    case BACKWARD_DELETE_CHAR:
+                    case VI_BACKWARD_DELETE_CHAR:
+                        if (searchBuffer.length() > 0) {
+                            searchBuffer.backspace();
+                        }
+                        break;
+                    case BACKWARD_KILL_WORD:
+                    case VI_BACKWARD_KILL_WORD:
+                        if (searchBuffer.length() > 0 && !isWhitespace(searchBuffer.prevChar())) {
+                            searchBuffer.backspace();
+                        }
+                        if (searchBuffer.length() > 0 && isWhitespace(searchBuffer.prevChar())) {
+                            searchBuffer.backspace();
+                        }
+                        break;
+                    case QUOTED_INSERT:
+                    case VI_QUOTED_INSERT:
+                        int c = readCharacter();
+                        if (c >= 0) {
+                            searchBuffer.write(c);
+                        } else {
+                            beep();
+                        }
+                        break;
+                    default:
+                        beep();
+                        break;
+                }
+            }
+        }
+    }
+
+    protected boolean insertCloseCurly() {
+        return insertClose("}");
+    }
+
+    protected boolean insertCloseParen() {
+        return insertClose(")");
+    }
+
+    protected boolean insertCloseSquare() {
+        return insertClose("]");
+    }
+
+    protected boolean insertClose(String s) {
+        putString(s);
+
+        long blink = getLong(BLINK_MATCHING_PAREN, DEFAULT_BLINK_MATCHING_PAREN);
+        if (blink <= 0) {
+            return true;
+        }
+
+        int closePosition = buf.cursor();
+
+        buf.move(-1);
+        doViMatchBracket();
+        redisplay();
+
+        peekCharacter(blink);
+
+        buf.cursor(closePosition);
+        return true;
+    }
+
+    protected boolean viMatchBracket() {
+        return doViMatchBracket();
+    }
+
+    protected boolean undefinedKey() {
+        return false;
+    }
+
+    /**
+     * Implements vi style bracket matching ("%" command). The matching
+     * bracket for the current bracket type that you are sitting on is matched.
+     *
+     * @return true if it worked, false if the cursor was not on a bracket
+     *   character or if there was no matching bracket.
+     */
+    protected boolean doViMatchBracket() {
+        int pos        = buf.cursor();
+
+        if (pos == buf.length()) {
+            return false;
+        }
+
+        int type       = getBracketType(buf.atChar(pos));
+        int move       = (type < 0) ? -1 : 1;
+        int count      = 1;
+
+        if (type == 0)
+            return false;
+
+        while (count > 0) {
+            pos += move;
+
+            // Fell off the start or end.
+            if (pos < 0 || pos >= buf.length()) {
+                return false;
+            }
+
+            int curType = getBracketType(buf.atChar(pos));
+            if (curType == type) {
+                ++count;
+            }
+            else if (curType == -type) {
+                --count;
+            }
+        }
+
+        /*
+         * Slight adjustment for delete-to, yank-to, change-to to ensure
+         * that the matching paren is consumed
+         */
+        if (move > 0 && isInViMoveOperation())
+            ++pos;
+
+        buf.cursor(pos);
+        return true;
+    }
+
+    /**
+     * Given a character determines what type of bracket it is (paren,
+     * square, curly, or none).
+     * @param ch The character to check
+     * @return 1 is square, 2 curly, 3 parent, or zero for none.  The value
+     *   will be negated if it is the closing form of the bracket.
+     */
+    protected int getBracketType (int ch) {
+        switch (ch) {
+            case '[': return  1;
+            case ']': return -1;
+            case '{': return  2;
+            case '}': return -2;
+            case '(': return  3;
+            case ')': return -3;
+            default:
+                return 0;
+        }
+    }
+
+    /**
+     * Performs character transpose. The character prior to the cursor and the
+     * character under the cursor are swapped and the cursor is advanced one.
+     * Do not cross line breaks.
+     * @return true
+     */
+    protected boolean transposeChars() {
+        int lstart = buf.cursor() - 1;
+        int lend = buf.cursor();
+        while (buf.atChar(lstart) != 0 && buf.atChar(lstart) != '\n') {
+            lstart--;
+        }
+        lstart++;
+        while (buf.atChar(lend) != 0 && buf.atChar(lend) != '\n') {
+            lend++;
+        }
+        if (lend - lstart < 2) {
+            return false;
+        }
+        boolean neg = this.count < 0;
+        for (int count = Math.max(this.count, -this.count); count > 0; --count) {
+            while (buf.cursor() <= lstart) {
+                buf.move(1);
+            }
+            while (buf.cursor() >= lend) {
+                buf.move(-1);
+            }
+            int c = buf.currChar();
+            buf.currChar(buf.prevChar());
+            buf.move(-1);
+            buf.currChar(c);
+            buf.move(neg ? 0 : 2);
+        }
+        return true;
+    }
+
+    protected boolean undo() {
+        isUndo = true;
+        if (undo.canUndo()) {
+            undo.undo();
+            return true;
+        }
+        return false;
+    }
+
+    protected boolean redo() {
+        isUndo = true;
+        if (undo.canRedo()) {
+            undo.redo();
+            return true;
+        }
+        return false;
+    }
+
+    protected boolean sendBreak() {
+        if (searchTerm == null) {
+            buf.clear();
+            println();
+            redrawLine();
+//            state = State.INTERRUPT;
+            return false;
+        }
+        return true;
+    }
+
+    protected boolean backwardChar() {
+        return buf.move(-count) != 0;
+    }
+
+    protected boolean forwardChar() {
+        return buf.move(count) != 0;
+    }
+
+    protected boolean viDigitOrBeginningOfLine() {
+        if (repeatCount > 0) {
+            return digitArgument();
+        } else {
+            return beginningOfLine();
+        }
+    }
+
+    protected boolean universalArgument() {
+        mult *= universal;
+        isArgDigit = true;
+        return true;
+    }
+
+    protected boolean argumentBase() {
+        if (repeatCount > 0 && repeatCount < 32) {
+            universal = repeatCount;
+            isArgDigit = true;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean negArgument() {
+        mult *= -1;
+        isArgDigit = true;
+        return true;
+    }
+
+    protected boolean digitArgument() {
+        String s = getLastBinding();
+        repeatCount = (repeatCount * 10) + s.charAt(s.length() - 1) - '0';
+        isArgDigit = true;
+        return true;
+    }
+
+    protected boolean viDelete() {
+        int cursorStart = buf.cursor();
+        Binding o = readBinding(getKeys());
+        if (o instanceof Reference) {
+            // TODO: be smarter on how to get the vi range
+            String op = viDeleteChangeYankToRemap(((Reference) o).name());
+            // This is a weird special case. In vi
+            // "dd" deletes the current line. So if we
+            // get a delete-to, followed by a delete-to,
+            // we delete the line.
+            if (VI_DELETE.equals(op)) {
+                killWholeLine();
+            } else {
+                viMoveMode = ViMoveMode.DELETE;
+                Widget widget = widgets.get(op);
+                if (widget != null && !widget.apply()) {
+                    viMoveMode = ViMoveMode.NORMAL;
+                    return false;
+                }
+                viMoveMode = ViMoveMode.NORMAL;
+            }
+            return viDeleteTo(cursorStart, buf.cursor());
+        } else {
+            pushBackBinding();
+            return false;
+        }
+    }
+
+    protected boolean viYankTo() {
+        int cursorStart = buf.cursor();
+        Binding o = readBinding(getKeys());
+        if (o instanceof Reference) {
+            // TODO: be smarter on how to get the vi range
+            String op = viDeleteChangeYankToRemap(((Reference) o).name());
+            // Similar to delete-to, a "yy" yanks the whole line.
+            if (VI_YANK.equals(op)) {
+                yankBuffer = buf.toString();
+                return true;
+            } else {
+                viMoveMode = ViMoveMode.YANK;
+                Widget widget = widgets.get(op);
+                if (widget != null && !widget.apply()) {
+                    return false;
+                }
+                viMoveMode = ViMoveMode.NORMAL;
+            }
+            return viYankTo(cursorStart, buf.cursor());
+        } else {
+            pushBackBinding();
+            return false;
+        }
+    }
+
+    protected boolean viYankWholeLine() {
+        int s, e;
+        int p = buf.cursor();
+        while (buf.move(-1) == -1 && buf.prevChar() != '\n') ;
+        s = buf.cursor();
+        for (int i = 0; i < repeatCount; i++) {
+            while (buf.move(1) == 1 && buf.prevChar() != '\n') ;
+        }
+        e = buf.cursor();
+        yankBuffer = buf.substring(s, e);
+        if (!yankBuffer.endsWith("\n")) {
+            yankBuffer += "\n";
+        }
+        buf.cursor(p);
+        return true;
+    }
+
+    protected boolean viChange() {
+        int cursorStart = buf.cursor();
+        Binding o = readBinding(getKeys());
+        if (o instanceof Reference) {
+            // TODO: be smarter on how to get the vi range
+            String op = viDeleteChangeYankToRemap(((Reference) o).name());
+            // change whole line
+            if (VI_CHANGE.equals(op)) {
+                killWholeLine();
+            } else {
+                viMoveMode = ViMoveMode.CHANGE;
+                Widget widget = widgets.get(op);
+                if (widget != null && !widget.apply()) {
+                    viMoveMode = ViMoveMode.NORMAL;
+                    return false;
+                }
+                viMoveMode = ViMoveMode.NORMAL;
+            }
+            boolean res = viChange(cursorStart, buf.cursor());
+            setKeyMap(VIINS);
+            return res;
+        } else {
+            pushBackBinding();
+            return false;
+        }
+    }
+
+    /*
+    protected int getViRange(Reference cmd, ViMoveMode mode) {
+        Buffer buffer = buf.copy();
+        int oldMark = mark;
+        int pos = buf.cursor();
+        String bind = getLastBinding();
+
+        if (visual != 0) {
+            if (buf.length() == 0) {
+                return -1;
+            }
+            pos = mark;
+            v
+        } else {
+            viMoveMode = mode;
+            mark = -1;
+            Binding b = bindingReader.readBinding(getKeys(), keyMaps.get(VIOPP));
+            if (b == null || new Reference(SEND_BREAK).equals(b)) {
+                viMoveMode = ViMoveMode.NORMAL;
+                mark = oldMark;
+                return -1;
+            }
+            if (cmd.equals(b)) {
+                doViLineRange();
+            }
+            Widget w = getWidget(b);
+            if (w )
+            if (b instanceof Reference) {
+
+            }
+        }
+
+    }
+    */
+
+    protected void cleanup() {
+        if (isSet(Option.ERASE_LINE_ON_FINISH)) {
+            Buffer oldBuffer = buf.copy();
+            AttributedString oldPrompt = prompt;
+            buf.clear();
+            prompt = new AttributedString("");
+            doCleanup(false);
+            prompt = oldPrompt;
+            buf.copyFrom(oldBuffer);
+        } else {
+            doCleanup(true);
+        }
+    }
+
+    protected void doCleanup(boolean nl) {
+        buf.cursor(buf.length());
+        post = null;
+        if (size.getColumns() > 0 || size.getRows() > 0) {
+            redisplay(false);
+            if (nl) {
+                println();
+            }
+            terminal.puts(Capability.keypad_local);
+            terminal.trackMouse(Terminal.MouseTracking.Off);
+            if (isSet(Option.BRACKETED_PASTE))
+                terminal.writer().write(BRACKETED_PASTE_OFF);
+            flush();
+        }
+        history.moveToEnd();
+    }
+
+    protected boolean historyIncrementalSearchForward() {
+        return doSearchHistory(false);
+    }
+
+    protected boolean historyIncrementalSearchBackward() {
+        return doSearchHistory(true);
+    }
+
+    static class Pair<U,V> {
+        final U u; final V v;
+        public Pair(U u, V v) {
+            this.u = u;
+            this.v = v;
+        }
+        public U getU() {
+            return u;
+        }
+        public V getV() {
+            return v;
+        }
+    }
+
+    protected boolean doSearchHistory(boolean backward) {
+        if (history.isEmpty()) {
+            return false;
+        }
+
+        KeyMap<Binding> terminators = new KeyMap<>();
+        getString(SEARCH_TERMINATORS, DEFAULT_SEARCH_TERMINATORS)
+                .codePoints().forEach(c -> bind(terminators, ACCEPT_LINE, new String(Character.toChars(c))));
+
+        Buffer originalBuffer = buf.copy();
+        searchIndex = -1;
+        searchTerm = new StringBuffer();
+        searchBackward = backward;
+        searchFailing = false;
+        post = () -> new AttributedString((searchFailing ? "failing" + " " : "")
+                        + (searchBackward ? "bck-i-search" : "fwd-i-search")
+                        + ": " + searchTerm + "_");
+
+        redisplay();
+        try {
+            while (true) {
+                int prevSearchIndex = searchIndex;
+                Binding operation = readBinding(getKeys(), terminators);
+                String ref = (operation instanceof Reference) ? ((Reference) operation).name() : "";
+                boolean next = false;
+                switch (ref) {
+                    case SEND_BREAK:
+                        beep();
+                        buf.copyFrom(originalBuffer);
+                        return true;
+                    case HISTORY_INCREMENTAL_SEARCH_BACKWARD:
+                        searchBackward = true;
+                        next = true;
+                        break;
+                    case HISTORY_INCREMENTAL_SEARCH_FORWARD:
+                        searchBackward = false;
+                        next = true;
+                        break;
+                    case BACKWARD_DELETE_CHAR:
+                        if (searchTerm.length() > 0) {
+                            searchTerm.deleteCharAt(searchTerm.length() - 1);
+                        }
+                        break;
+                    case SELF_INSERT:
+                        searchTerm.append(getLastBinding());
+                        break;
+                    default:
+                        // Set buffer and cursor position to the found string.
+                        if (searchIndex != -1) {
+                            history.moveTo(searchIndex);
+                        }
+                        pushBackBinding();
+                        return true;
+                }
+
+                // print the search status
+                String pattern = doGetSearchPattern();
+                if (pattern.length() == 0) {
+                    buf.copyFrom(originalBuffer);
+                    searchFailing = false;
+                } else {
+                    boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE_SEARCH);
+                    Pattern pat = Pattern.compile(pattern, caseInsensitive ? Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE
+                                                                           : Pattern.UNICODE_CASE);
+                    Pair<Integer, Integer> pair = null;
+                    if (searchBackward) {
+                        boolean nextOnly = next;
+                        pair = matches(pat, buf.toString(), searchIndex).stream()
+                                .filter(p -> nextOnly ? p.v < buf.cursor() : p.v <= buf.cursor())
+                                .max(Comparator.comparing(Pair::getV))
+                                .orElse(null);
+                        if (pair == null) {
+                            pair = StreamSupport.stream(
+                                    Spliterators.spliteratorUnknownSize(history.reverseIterator(searchIndex < 0 ? history.last() : searchIndex - 1), Spliterator.ORDERED), false)
+                                    .flatMap(e -> matches(pat, e.line(), e.index()).stream())
+                                    .findFirst()
+                                    .orElse(null);
+                        }
+                    } else {
+                        boolean nextOnly = next;
+                        pair = matches(pat, buf.toString(), searchIndex).stream()
+                                .filter(p -> nextOnly ? p.v > buf.cursor() : p.v >= buf.cursor())
+                                .min(Comparator.comparing(Pair::getV))
+                                .orElse(null);
+                        if (pair == null) {
+                            pair = StreamSupport.stream(
+                                    Spliterators.spliteratorUnknownSize(history.iterator((searchIndex < 0 ? history.last() : searchIndex) + 1), Spliterator.ORDERED), false)
+                                    .flatMap(e -> matches(pat, e.line(), e.index()).stream())
+                                    .findFirst()
+                                    .orElse(null);
+                            if (pair == null && searchIndex >= 0) {
+                                pair = matches(pat, originalBuffer.toString(), -1).stream()
+                                        .min(Comparator.comparing(Pair::getV))
+                                        .orElse(null);
+                            }
+                        }
+                    }
+                    if (pair != null) {
+                        searchIndex = pair.u;
+                        buf.clear();
+                        if (searchIndex >= 0) {
+                            buf.write(history.get(searchIndex));
+                        } else {
+                            buf.write(originalBuffer.toString());
+                        }
+                        buf.cursor(pair.v);
+                        searchFailing = false;
+                    } else {
+                        searchFailing = true;
+                        beep();
+                    }
+                }
+                redisplay();
+            }
+        } catch (IOError e) {
+            // Ignore Ctrl+C interrupts and just exit the loop
+            if (!(e.getCause() instanceof InterruptedException)) {
+                throw e;
+            }
+            return true;
+        } finally {
+            searchTerm = null;
+            searchIndex = -1;
+            post = null;
+        }
+    }
+
+    private List<Pair<Integer, Integer>> matches(Pattern p, String line, int index) {
+        List<Pair<Integer, Integer>> starts = new ArrayList<>();
+        Matcher m = p.matcher(line);
+        while (m.find()) {
+            starts.add(new Pair<>(index, m.start()));
+        }
+        return starts;
+   }
+
+    private String doGetSearchPattern() {
+        StringBuilder sb = new StringBuilder();
+        boolean inQuote = false;
+        for (int i = 0; i < searchTerm.length(); i++) {
+            char c = searchTerm.charAt(i);
+            if (Character.isLowerCase(c)) {
+                if (inQuote) {
+                    sb.append("\\E");
+                    inQuote = false;
+                }
+                sb.append("[").append(Character.toLowerCase(c)).append(Character.toUpperCase(c)).append("]");
+            } else {
+                if (!inQuote) {
+                    sb.append("\\Q");
+                    inQuote = true;
+                }
+                sb.append(c);
+            }
+        }
+        if (inQuote) {
+            sb.append("\\E");
+        }
+        return sb.toString();
+    }
+
+    private void pushBackBinding() {
+        pushBackBinding(false);
+    }
+
+    private void pushBackBinding(boolean skip) {
+        String s = getLastBinding();
+        if (s != null) {
+            bindingReader.runMacro(s);
+            skipRedisplay = skip;
+        }
+    }
+
+    protected boolean historySearchForward() {
+        if (historyBuffer == null || buf.length() == 0
+                || !buf.toString().equals(history.current())) {
+            historyBuffer = buf.copy();
+            searchBuffer = getFirstWord();
+        }
+        int index = history.index() + 1;
+
+        if (index < history.last() + 1) {
+            int searchIndex = searchForwards(searchBuffer.toString(), index, true);
+            if (searchIndex == -1) {
+                history.moveToEnd();
+                if (!buf.toString().equals(historyBuffer.toString())) {
+                    setBuffer(historyBuffer.toString());
+                    historyBuffer = null;
+                } else {
+                    return false;
+                }
+            } else {
+                // Maintain cursor position while searching.
+                if (history.moveTo(searchIndex)) {
+                    setBuffer(history.current());
+                } else {
+                    history.moveToEnd();
+                    setBuffer(historyBuffer.toString());
+                    return false;
+                }
+            }
+        } else {
+            history.moveToEnd();
+            if (!buf.toString().equals(historyBuffer.toString())) {
+                setBuffer(historyBuffer.toString());
+                historyBuffer = null;
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private CharSequence getFirstWord() {
+        String s = buf.toString();
+        int i = 0;
+        while (i < s.length() && !Character.isWhitespace(s.charAt(i))) {
+            i++;
+        }
+        return s.substring(0, i);
+    }
+
+    protected boolean historySearchBackward() {
+        if (historyBuffer == null || buf.length() == 0
+                || !buf.toString().equals(history.current())) {
+            historyBuffer = buf.copy();
+            searchBuffer = getFirstWord();
+        }
+        int searchIndex = searchBackwards(searchBuffer.toString(), history.index(), true);
+
+        if (searchIndex == -1) {
+            return false;
+        } else {
+            // Maintain cursor position while searching.
+            if (history.moveTo(searchIndex)) {
+                setBuffer(history.current());
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    //
+    // History search
+    //
+    /**
+     * Search backward in history from a given position.
+     *
+     * @param searchTerm substring to search for.
+     * @param startIndex the index from which on to search
+     * @return index where this substring has been found, or -1 else.
+     */
+    public int searchBackwards(String searchTerm, int startIndex) {
+        return searchBackwards(searchTerm, startIndex, false);
+    }
+
+    /**
+     * Search backwards in history from the current position.
+     *
+     * @param searchTerm substring to search for.
+     * @return index where the substring has been found, or -1 else.
+     */
+    public int searchBackwards(String searchTerm) {
+        return searchBackwards(searchTerm, history.index(), false);
+    }
+
+    public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
+        boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE_SEARCH);
+        if (caseInsensitive) {
+            searchTerm = searchTerm.toLowerCase();
+        }
+        ListIterator<History.Entry> it = history.iterator(startIndex);
+        while (it.hasPrevious()) {
+            History.Entry e = it.previous();
+            String line = e.line();
+            if (caseInsensitive) {
+                line = line.toLowerCase();
+            }
+            int idx = line.indexOf(searchTerm);
+            if ((startsWith && idx == 0) || (!startsWith && idx >= 0)) {
+                return e.index();
+            }
+        }
+        return -1;
+    }
+
+    public int searchForwards(String searchTerm, int startIndex, boolean startsWith) {
+        boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE_SEARCH);
+        if (caseInsensitive) {
+            searchTerm = searchTerm.toLowerCase();
+        }
+        if (startIndex > history.last()) {
+            startIndex = history.last();
+        }
+        ListIterator<History.Entry> it = history.iterator(startIndex);
+        if (searchIndex != -1 && it.hasNext()) {
+            it.next();
+        }
+        while (it.hasNext()) {
+            History.Entry e = it.next();
+            String line = e.line();
+            if (caseInsensitive) {
+                line = line.toLowerCase();
+            }
+            int idx = line.indexOf(searchTerm);
+            if ((startsWith && idx == 0) || (!startsWith && idx >= 0)) {
+                return e.index();
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Search forward in history from a given position.
+     *
+     * @param searchTerm substring to search for.
+     * @param startIndex the index from which on to search
+     * @return index where this substring has been found, or -1 else.
+     */
+    public int searchForwards(String searchTerm, int startIndex) {
+        return searchForwards(searchTerm, startIndex, false);
+    }
+    /**
+     * Search forwards in history from the current position.
+     *
+     * @param searchTerm substring to search for.
+     * @return index where the substring has been found, or -1 else.
+     */
+    public int searchForwards(String searchTerm) {
+        return searchForwards(searchTerm, history.index());
+    }
+
+    protected boolean quit() {
+        getBuffer().clear();
+        return acceptLine();
+    }
+
+    protected boolean acceptLine() {
+        parsedLine = null;
+        if (!isSet(Option.DISABLE_EVENT_EXPANSION)) {
+            try {
+                String str = buf.toString();
+                String exp = expander.expandHistory(history, str);
+                if (!exp.equals(str)) {
+                    buf.clear();
+                    buf.write(exp);
+                    if (isSet(Option.HISTORY_VERIFY)) {
+                        return true;
+                    }
+                }
+            } catch (IllegalArgumentException e) {
+                // Ignore
+            }
+        }
+        try {
+            parsedLine = parser.parse(buf.toString(), buf.cursor(), ParseContext.ACCEPT_LINE);
+        } catch (EOFError e) {
+            buf.write("\n");
+            return true;
+        } catch (SyntaxError e) {
+            // do nothing
+        }
+        callWidget(CALLBACK_FINISH);
+        state = State.DONE;
+        return true;
+    }
+
+    protected boolean selfInsert() {
+        for (int count = this.count; count > 0; count--) {
+            putString(getLastBinding());
+        }
+        return true;
+    }
+
+    protected boolean selfInsertUnmeta() {
+        if (getLastBinding().charAt(0) == '\u001b') {
+            String s = getLastBinding().substring(1);
+            if ("\r".equals(s)) {
+                s = "\n";
+            }
+            for (int count = this.count; count > 0; count--) {
+                putString(s);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean overwriteMode() {
+        overTyping = !overTyping;
+        return true;
+    }
+
+
+    //
+    // History Control
+    //
+
+    protected boolean beginningOfBufferOrHistory() {
+        if (findbol() != 0) {
+            buf.cursor(0);
+            return true;
+        } else {
+            return beginningOfHistory();
+        }
+    }
+
+    protected boolean beginningOfHistory() {
+        if (history.moveToFirst()) {
+            setBuffer(history.current());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean endOfBufferOrHistory() {
+        if (findeol() != buf.length()) {
+            buf.cursor(buf.length());
+            return true;
+        } else {
+            return endOfHistory();
+        }
+    }
+
+    protected boolean endOfHistory() {
+        if (history.moveToLast()) {
+            setBuffer(history.current());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean beginningOfLineHist() {
+        if (count < 0) {
+            return callNeg(this::endOfLineHist);
+        }
+        while (count-- > 0) {
+            int bol = findbol();
+            if (bol != buf.cursor()) {
+                buf.cursor(bol);
+            } else {
+                moveHistory(false);
+                buf.cursor(0);
+            }
+        }
+        return true;
+    }
+
+    protected boolean endOfLineHist() {
+        if (count < 0) {
+            return callNeg(this::beginningOfLineHist);
+        }
+        while (count-- > 0) {
+            int eol = findeol();
+            if (eol != buf.cursor()) {
+                buf.cursor(eol);
+            } else {
+                moveHistory(true);
+            }
+        }
+        return true;
+    }
+
+    protected boolean upHistory() {
+        while (count-- > 0) {
+            if (!moveHistory(false)) {
+                return !isSet(Option.HISTORY_BEEP);
+            }
+        }
+        return true;
+    }
+
+    protected boolean downHistory() {
+        while (count-- > 0) {
+            if (!moveHistory(true)) {
+                return !isSet(Option.HISTORY_BEEP);
+            }
+        }
+        return true;
+    }
+
+    protected boolean viUpLineOrHistory() {
+        return upLine()
+                || upHistory() && viFirstNonBlank();
+    }
+
+    protected boolean viDownLineOrHistory() {
+        return downLine()
+                || downHistory() && viFirstNonBlank();
+    }
+
+    protected boolean upLine() {
+        return buf.up();
+    }
+
+    protected boolean downLine() {
+        return buf.down();
+    }
+
+    protected boolean upLineOrHistory() {
+        return upLine() || upHistory();
+    }
+
+    protected boolean upLineOrSearch() {
+        return upLine() || historySearchBackward();
+    }
+
+    protected boolean downLineOrHistory() {
+        return downLine() || downHistory();
+    }
+
+    protected boolean downLineOrSearch() {
+        return downLine() || historySearchForward();
+    }
+
+    protected boolean viCmdMode() {
+        // If we are re-entering move mode from an
+        // aborted yank-to, delete-to, change-to then
+        // don't move the cursor back. The cursor is
+        // only move on an explicit entry to movement
+        // mode.
+        if (state == State.NORMAL) {
+            buf.move(-1);
+        }
+        return setKeyMap(VICMD);
+    }
+
+    protected boolean viInsert() {
+        return setKeyMap(VIINS);
+    }
+
+    protected boolean viAddNext() {
+        buf.move(1);
+        return setKeyMap(VIINS);
+    }
+
+    protected boolean viAddEol() {
+        return endOfLine() && setKeyMap(VIINS);
+    }
+
+    protected boolean emacsEditingMode() {
+        return setKeyMap(EMACS);
+    }
+
+    protected boolean viChangeWholeLine() {
+        return viFirstNonBlank() && viChangeEol();
+    }
+
+    protected boolean viChangeEol() {
+        return viChange(buf.cursor(), buf.length())
+                && setKeyMap(VIINS);
+    }
+
+    protected boolean viKillEol() {
+        int eol = findeol();
+        if (buf.cursor() == eol) {
+            return false;
+        }
+        killRing.add(buf.substring(buf.cursor(), eol));
+        buf.delete(eol - buf.cursor());
+        return true;
+    }
+
+    protected boolean quotedInsert() {
+        int c = readCharacter();
+        while (count-- > 0) {
+            putString(new String(Character.toChars(c)));
+        }
+        return true;
+    }
+
+    protected boolean viJoin() {
+        if (buf.down()) {
+            while (buf.move(-1) == -1 && buf.prevChar() != '\n') ;
+            buf.backspace();
+            buf.write(' ');
+            buf.move(-1);
+            return true;
+        }
+        return false;
+    }
+
+    protected boolean viKillWholeLine() {
+        return killWholeLine() && setKeyMap(VIINS);
+    }
+
+    protected boolean viInsertBol() {
+        return beginningOfLine() && setKeyMap(VIINS);
+    }
+
+    protected boolean backwardDeleteChar() {
+        if (count < 0) {
+            return callNeg(this::deleteChar);
+        }
+        if (buf.cursor() == 0) {
+            return false;
+        }
+        buf.backspace(count);
+        return true;
+    }
+
+    protected boolean viFirstNonBlank() {
+        beginningOfLine();
+        while (buf.cursor() < buf.length() && isWhitespace(buf.currChar())) {
+            buf.move(1);
+        }
+        return true;
+    }
+
+    protected boolean viBeginningOfLine() {
+        buf.cursor(findbol());
+        return true;
+    }
+
+    protected boolean viEndOfLine() {
+        if (count < 0) {
+            return false;
+        }
+        while (count-- > 0) {
+            buf.cursor(findeol() + 1);
+        }
+        buf.move(-1);
+        return true;
+    }
+
+    protected boolean beginningOfLine() {
+        while (count-- > 0) {
+            while (buf.move(-1) == -1 && buf.prevChar() != '\n') ;
+        }
+        return true;
+    }
+
+    protected boolean endOfLine() {
+        while (count-- > 0) {
+            while (buf.move(1) == 1 && buf.currChar() != '\n') ;
+        }
+        return true;
+    }
+
+    protected boolean deleteChar() {
+        if (count < 0) {
+            return callNeg(this::backwardDeleteChar);
+        }
+        if (buf.cursor() == buf.length()) {
+            return false;
+        }
+        buf.delete(count);
+        return true;
+    }
+
+    /**
+     * Deletes the previous character from the cursor position
+     * @return <code>true</code> if it succeeded, <code>false</code> otherwise
+     */
+    protected boolean viBackwardDeleteChar() {
+        for (int i = 0; i < count; i++) {
+            if (!buf.backspace()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Deletes the character you are sitting on and sucks the rest of
+     * the line in from the right.
+     * @return <code>true</code> if it succeeded, <code>false</code> otherwise
+     */
+    protected boolean viDeleteChar() {
+        for (int i = 0; i < count; i++) {
+            if (!buf.delete()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Switches the case of the current character from upper to lower
+     * or lower to upper as necessary and advances the cursor one
+     * position to the right.
+     * @return <code>true</code> if it succeeded, <code>false</code> otherwise
+     */
+    protected boolean viSwapCase() {
+        for (int i = 0; i < count; i++) {
+            if (buf.cursor() < buf.length()) {
+                int ch = buf.atChar(buf.cursor());
+                ch = switchCase(ch);
+                buf.currChar(ch);
+                buf.move(1);
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Implements the vi change character command (in move-mode "r"
+     * followed by the character to change to).
+     * @return <code>true</code> if it succeeded, <code>false</code> otherwise
+     */
+    protected boolean viReplaceChars() {
+        int c = readCharacter();
+        // EOF, ESC, or CTRL-C aborts.
+        if (c < 0 || c == '\033' || c == '\003') {
+            return true;
+        }
+
+        for (int i = 0; i < count; i++) {
+            if (buf.currChar((char) c)) {
+                if (i < count - 1) {
+                    buf.move(1);
+                }
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected boolean viChange(int startPos, int endPos) {
+        return doViDeleteOrChange(startPos, endPos, true);
+    }
+
+    protected boolean viDeleteTo(int startPos, int endPos) {
+        return doViDeleteOrChange(startPos, endPos, false);
+    }
+
+    /**
+     * Performs the vi "delete-to" action, deleting characters between a given
+     * span of the input line.
+     * @param startPos The start position
+     * @param endPos The end position.
+     * @param isChange If true, then the delete is part of a change operationg
+     *    (e.g. "c$" is change-to-end-of line, so we first must delete to end
+     *    of line to start the change
+     * @return <code>true</code> if it succeeded, <code>false</code> otherwise
+     */
+    protected boolean doViDeleteOrChange(int startPos, int endPos, boolean isChange) {
+        if (startPos == endPos) {
+            return true;
+        }
+
+        if (endPos < startPos) {
+            int tmp = endPos;
+            endPos = startPos;
+            startPos = tmp;
+        }
+
+        buf.cursor(startPos);
+        buf.delete(endPos - startPos);
+
+        // If we are doing a delete operation (e.g. "d$") then don't leave the
+        // cursor dangling off the end. In reality the "isChange" flag is silly
+        // what is really happening is that if we are in "move-mode" then the
+        // cursor can't be moved off the end of the line, but in "edit-mode" it
+        // is ok, but I have no easy way of knowing which mode we are in.
+        if (! isChange && startPos > 0 && startPos == buf.length()) {
+            buf.move(-1);
+        }
+        return true;
+    }
+
+    /**
+     * Implement the "vi" yank-to operation.  This operation allows you
+     * to yank the contents of the current line based upon a move operation,
+     * for example "yw" yanks the current word, "3yw" yanks 3 words, etc.
+     *
+     * @param startPos The starting position from which to yank
+     * @param endPos The ending position to which to yank
+     * @return <code>true</code> if the yank succeeded
+     */
+    protected boolean viYankTo(int startPos, int endPos) {
+        int cursorPos = startPos;
+
+        if (endPos < startPos) {
+            int tmp = endPos;
+            endPos = startPos;
+            startPos = tmp;
+        }
+
+        if (startPos == endPos) {
+            yankBuffer = "";
+            return true;
+        }
+
+        yankBuffer = buf.substring(startPos, endPos);
+
+        /*
+         * It was a movement command that moved the cursor to find the
+         * end position, so put the cursor back where it started.
+         */
+        buf.cursor(cursorPos);
+        return true;
+    }
+
+    protected boolean viOpenLineAbove() {
+        while (buf.move(-1) == -1 && buf.prevChar() != '\n') ;
+        buf.write('\n');
+        buf.move(-1);
+        return setKeyMap(VIINS);
+    }
+
+    protected boolean viOpenLineBelow() {
+        while (buf.move(1) == 1 && buf.currChar() != '\n') ;
+        buf.write('\n');
+        return setKeyMap(VIINS);
+    }
+
+    /**
+     * Pasts the yank buffer to the right of the current cursor position
+     * and moves the cursor to the end of the pasted region.
+     * @return <code>true</code>
+     */
+    protected boolean viPutAfter() {
+        if (yankBuffer.indexOf('\n') >= 0) {
+            while (buf.move(1) == 1 && buf.currChar() != '\n');
+            buf.move(1);
+            putString(yankBuffer);
+            buf.move(- yankBuffer.length());
+        } else if (yankBuffer.length () != 0) {
+            if (buf.cursor() < buf.length()) {
+                buf.move(1);
+            }
+            for (int i = 0; i < count; i++) {
+                putString(yankBuffer);
+            }
+            buf.move(-1);
+        }
+        return true;
+    }
+
+    protected boolean viPutBefore() {
+        if (yankBuffer.indexOf('\n') >= 0) {
+            while (buf.move(-1) == -1 && buf.prevChar() != '\n');
+            putString(yankBuffer);
+            buf.move(- yankBuffer.length());
+        } else if (yankBuffer.length () != 0) {
+            if (buf.cursor() > 0) {
+                buf.move(-1);
+            }
+            for (int i = 0; i < count; i++) {
+                putString(yankBuffer);
+            }
+            buf.move(-1);
+        }
+        return true;
+    }
+
+    protected boolean doLowercaseVersion() {
+        bindingReader.runMacro(getLastBinding().toLowerCase());
+        return true;
+    }
+
+    protected boolean setMarkCommand() {
+        if (count < 0) {
+            regionActive = RegionType.NONE;
+            return true;
+        }
+        regionMark = buf.cursor();
+        regionActive = RegionType.CHAR;
+        return true;
+    }
+
+    protected boolean exchangePointAndMark() {
+        if (count == 0) {
+            regionActive = RegionType.CHAR;
+            return true;
+        }
+        int x = regionMark;
+        regionMark = buf.cursor();
+        buf.cursor(x);
+        if (buf.cursor() > buf.length()) {
+            buf.cursor(buf.length());
+        }
+        if (count > 0) {
+            regionActive = RegionType.CHAR;
+        }
+        return true;
+    }
+
+    protected boolean visualMode() {
+        if (isInViMoveOperation()) {
+            isArgDigit = true;
+            forceLine = false;
+            forceChar = true;
+            return true;
+        }
+        if (regionActive == RegionType.NONE) {
+            regionMark = buf.cursor();
+            regionActive = RegionType.CHAR;
+        } else if (regionActive == RegionType.CHAR) {
+            regionActive = RegionType.NONE;
+        } else if (regionActive == RegionType.LINE) {
+            regionActive = RegionType.CHAR;
+        }
+        return true;
+    }
+
+    protected boolean visualLineMode() {
+        if (isInViMoveOperation()) {
+            isArgDigit = true;
+            forceLine = true;
+            forceChar = false;
+            return true;
+        }
+        if (regionActive == RegionType.NONE) {
+            regionMark = buf.cursor();
+            regionActive = RegionType.LINE;
+        } else if (regionActive == RegionType.CHAR) {
+            regionActive = RegionType.LINE;
+        } else if (regionActive == RegionType.LINE) {
+            regionActive = RegionType.NONE;
+        }
+        return true;
+    }
+
+    protected boolean deactivateRegion() {
+        regionActive = RegionType.NONE;
+        return true;
+    }
+
+    protected boolean whatCursorPosition() {
+        post = () -> {
+            AttributedStringBuilder sb = new AttributedStringBuilder();
+            if (buf.cursor() < buf.length()) {
+                int c = buf.currChar();
+                sb.append("Char: ");
+                if (c == ' ') {
+                    sb.append("SPC");
+                } else if (c == '\n') {
+                    sb.append("LFD");
+                } else if (c < 32) {
+                    sb.append('^');
+                    sb.append((char) (c + 'A' - 1));
+                } else if (c == 127) {
+                    sb.append("^?");
+                } else {
+                    sb.append((char) c);
+                }
+                sb.append(" (");
+                sb.append("0").append(Integer.toOctalString(c)).append(" ");
+                sb.append(Integer.toString(c)).append(" ");
+                sb.append("0x").append(Integer.toHexString(c)).append(" ");
+                sb.append(")");
+            } else {
+                sb.append("EOF");
+            }
+            sb.append("   ");
+            sb.append("point ");
+            sb.append(Integer.toString(buf.cursor() + 1));
+            sb.append(" of ");
+            sb.append(Integer.toString(buf.length() + 1));
+            sb.append(" (");
+            sb.append(Integer.toString(buf.length() == 0 ? 100 : ((100 * buf.cursor()) / buf.length())));
+            sb.append("%)");
+            sb.append("   ");
+            sb.append("column ");
+            sb.append(Integer.toString(buf.cursor() - findbol()));
+            return sb.toAttributedString();
+        };
+        return true;
+    }
+
+    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);
+        return widgets;
+    }
+
+    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) {
+                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);
+    }
+
+    private void concat(List<AttributedString> lines, AttributedStringBuilder sb) {
+        if (lines.size() > 1) {
+            for (int i = 0; i < lines.size() - 1; i++) {
+                sb.append(lines.get(i));
+                sb.style(sb.style().inverse());
+                sb.append("\\n");
+                sb.style(sb.style().inverseOff());
+            }
+        }
+        sb.append(lines.get(lines.size() - 1));
+    }
+
+    /**
+     * Compute the full string to be displayed with the left, right and secondary prompts
+     * @param secondaryPrompts a list to store the secondary prompts
+     * @return the displayed string including the buffer, left prompts and the help below
+     */
+    public AttributedString getDisplayedBufferWithPrompts(List<AttributedString> secondaryPrompts) {
+        AttributedString attBuf = getHighlightedBuffer(buf.toString());
+
+        AttributedString tNewBuf = insertSecondaryPrompts(attBuf, secondaryPrompts);
+        AttributedStringBuilder full = new AttributedStringBuilder().tabs(TAB_WIDTH);
+        full.append(prompt);
+        full.append(tNewBuf);
+        if (post != null) {
+            full.append("\n");
+            full.append(post.get());
+        }
+        return full.toAttributedString();
+    }
+
+    private AttributedString getHighlightedBuffer(String buffer) {
+        if (maskingCallback != null) {
+            buffer = maskingCallback.display(buffer);
+        }
+        if (highlighter != null && !isSet(Option.DISABLE_HIGHLIGHTER)) {
+            return highlighter.highlight(this, buffer);
+        }
+        return new AttributedString(buffer);
+    }
+
+    private AttributedString expandPromptPattern(String pattern, int padToWidth,
+                                                 String message, int line) {
+        ArrayList<AttributedString> parts = new ArrayList<>();
+        boolean isHidden = false;
+        int padPartIndex = -1;
+        StringBuilder padPartString = null;
+        StringBuilder sb = new StringBuilder();
+        // Add "%{" to avoid special case for end of string.
+        pattern = pattern + "%{";
+        int plen = pattern.length();
+        int padChar = -1;
+        int padPos = -1;
+        int cols = 0;
+        for (int i = 0; i < plen; ) {
+            char ch = pattern.charAt(i++);
+            if (ch == '%' && i < plen) {
+                int count = 0;
+                boolean countSeen = false;
+                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 == '{';
+                            break decode;
+                        case '%':
+                            sb.append(ch);
+                            break decode;
+                        case 'N':
+                            sb.append(getInt(LINE_OFFSET, 0) + line);
+                            break decode;
+                        case 'M':
+                            if (message != null)
+                                sb.append(message);
+                            break decode;
+                        case 'P':
+                            if (countSeen && count >= 0)
+                                padToWidth = count;
+                            if (i < plen) {
+                                padChar = pattern.charAt(i++);
+                                // FIXME check surrogate
+                            }
+                            padPos = sb.length();
+                            padPartIndex = parts.size();
+                            break decode;
+                        case '-':
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
+                            boolean neg = false;
+                            if (ch == '-') {
+                                neg = true;
+                                ch = pattern.charAt(i++);
+                            }
+                            countSeen = true;
+                            count = 0;
+                            while (ch >= '0' && ch <= '9') {
+                                count = (count < 0 ? 0 : 10 * count) + (ch - '0');
+                                ch = pattern.charAt(i++);
+                            }
+                            if (neg) {
+                                count = -count;
+                            }
+                            i--;
+                            break;
+                        default:
+                            break decode;
+                    }
+                }
+            } else
+                sb.append(ch);
+        }
+        if (padToWidth > cols) {
+            int padCharCols = WCWidth.wcwidth(padChar);
+            int padCount = (padToWidth - cols) / padCharCols;
+            sb = padPartString;
+            while (--padCount >= 0)
+                sb.insert(padPos, (char) padChar); // FIXME if wide
+            parts.set(padPartIndex, AttributedString.fromAnsi(sb.toString()));
+        }
+        return AttributedString.join(null, parts);
+    }
+
+    private AttributedString insertSecondaryPrompts(AttributedString str, List<AttributedString> prompts) {
+        return insertSecondaryPrompts(str, prompts, true);
+    }
+
+    private AttributedString insertSecondaryPrompts(AttributedString strAtt, List<AttributedString> prompts, boolean computePrompts) {
+        Objects.requireNonNull(prompts);
+        List<AttributedString> lines = strAtt.columnSplitLength(Integer.MAX_VALUE);
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        String secondaryPromptPattern = getString(SECONDARY_PROMPT_PATTERN, DEFAULT_SECONDARY_PROMPT_PATTERN);
+        boolean needsMessage = secondaryPromptPattern.contains("%M");
+        AttributedStringBuilder buf = new AttributedStringBuilder();
+        int width = 0;
+        List<String> missings = new ArrayList<>();
+        if (computePrompts && secondaryPromptPattern.contains("%P")) {
+            width = prompt.columnLength();
+            for (int line = 0; line < lines.size() - 1; line++) {
+                AttributedString prompt;
+                buf.append(lines.get(line)).append("\n");
+                String missing = "";
+                if (needsMessage) {
+                    try {
+                        parser.parse(buf.toString(), buf.length(), ParseContext.SECONDARY_PROMPT);
+                    } catch (EOFError e) {
+                        missing = e.getMissing();
+                    } catch (SyntaxError e) {
+                        // Ignore
+                    }
+                }
+                missings.add(missing);
+                prompt = expandPromptPattern(secondaryPromptPattern, 0, missing, line + 1);
+                width = Math.max(width, prompt.columnLength());
+            }
+            buf.setLength(0);
+        }
+        int line = 0;
+        while (line < lines.size() - 1) {
+            sb.append(lines.get(line)).append("\n");
+            buf.append(lines.get(line)).append("\n");
+            AttributedString prompt;
+            if (computePrompts) {
+                String missing = "";
+                if (needsMessage) {
+                    if (missings.isEmpty()) {
+                        try {
+                            parser.parse(buf.toString(), buf.length(), ParseContext.SECONDARY_PROMPT);
+                        } catch (EOFError e) {
+                            missing = e.getMissing();
+                        } catch (SyntaxError e) {
+                            // Ignore
+                        }
+                    } else {
+                        missing = missings.get(line);
+                    }
+                }
+                prompt = expandPromptPattern(secondaryPromptPattern, width, missing, line + 1);
+            } else {
+                prompt = prompts.get(line);
+            }
+            prompts.add(prompt);
+            sb.append(prompt);
+            line++;
+        }
+        sb.append(lines.get(line));
+        buf.append(lines.get(line));
+        return sb.toAttributedString();
+    }
+
+    private AttributedString addRightPrompt(AttributedString prompt, AttributedString line) {
+        int width = prompt.columnLength();
+        boolean endsWithNl = line.length() > 0
+            && line.charAt(line.length() - 1) == '\n';
+        // columnLength counts -1 for the final newline; adjust for that
+        int nb = size.getColumns() - width
+            - (line.columnLength() + (endsWithNl ? 1 : 0));
+        if (nb >= 3) {
+            AttributedStringBuilder sb = new AttributedStringBuilder(size.getColumns());
+            sb.append(line, 0, endsWithNl ? line.length() - 1 : line.length());
+            for (int j = 0; j < nb; j++) {
+                sb.append(' ');
+            }
+            sb.append(prompt);
+            if (endsWithNl) {
+                sb.append('\n');
+            }
+            line = sb.toAttributedString();
+        }
+        return line;
+    }
+
+    //
+    // Completion
+    //
+
+    protected boolean insertTab() {
+        return isSet(Option.INSERT_TAB)
+                    && getLastBinding().equals("\t")
+                    && buf.toString().matches("(^|[\\s\\S]*\n)[\r\n\t ]*");
+    }
+
+    protected boolean expandHistory() {
+        String str = buf.toString();
+        String exp = expander.expandHistory(history, str);
+        if (!exp.equals(str)) {
+            buf.clear();
+            buf.write(exp);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected enum CompletionType {
+        Expand,
+        ExpandComplete,
+        Complete,
+        List,
+    }
+
+    protected boolean expandWord() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.Expand, isSet(Option.MENU_COMPLETE), false);
+        }
+    }
+
+    protected boolean expandOrComplete() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.ExpandComplete, isSet(Option.MENU_COMPLETE), false);
+        }
+    }
+
+    protected boolean expandOrCompletePrefix() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.ExpandComplete, isSet(Option.MENU_COMPLETE), true);
+        }
+    }
+
+    protected boolean completeWord() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.Complete, isSet(Option.MENU_COMPLETE), false);
+        }
+    }
+
+    protected boolean menuComplete() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.Complete, true, false);
+        }
+    }
+
+    protected boolean menuExpandOrComplete() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.ExpandComplete, true, false);
+        }
+    }
+
+    protected boolean completePrefix() {
+        if (insertTab()) {
+            return selfInsert();
+        } else {
+            return doComplete(CompletionType.Complete, isSet(Option.MENU_COMPLETE), true);
+        }
+    }
+
+    protected boolean listChoices() {
+        return doComplete(CompletionType.List, isSet(Option.MENU_COMPLETE), false);
+    }
+
+    protected boolean deleteCharOrList() {
+        if (buf.cursor() != buf.length() || buf.length() == 0) {
+            return deleteChar();
+        } else {
+            return doComplete(CompletionType.List, isSet(Option.MENU_COMPLETE), false);
+        }
+    }
+
+    protected boolean doComplete(CompletionType lst, boolean useMenu, boolean prefix) {
+        // If completion is disabled, just bail out
+        if (getBoolean(DISABLE_COMPLETION, false)) {
+            return true;
+        }
+        // Try to expand history first
+        // If there is actually an expansion, bail out now
+        if (!isSet(Option.DISABLE_EVENT_EXPANSION)) {
+            try {
+                if (expandHistory()) {
+                    return true;
+                }
+            } catch (Exception e) {
+                Log.info("Error while expanding history", e);
+                return false;
+            }
+        }
+
+        // Parse the command line
+        CompletingParsedLine line;
+        try {
+            line = wrap(parser.parse(buf.toString(), buf.cursor(), ParseContext.COMPLETE));
+        } catch (Exception e) {
+            Log.info("Error while parsing line", e);
+            return false;
+        }
+
+        // Find completion candidates
+        List<Candidate> candidates = new ArrayList<>();
+        try {
+            if (completer != null) {
+                completer.complete(this, line, candidates);
+            }
+        } catch (Exception e) {
+            Log.info("Error while finding completion candidates", e);
+            return false;
+        }
+
+        if (lst == CompletionType.ExpandComplete || lst == CompletionType.Expand) {
+            String w = expander.expandVar(line.word());
+            if (!line.word().equals(w)) {
+                if (prefix) {
+                    buf.backspace(line.wordCursor());
+                } else {
+                    buf.move(line.word().length() - line.wordCursor());
+                    buf.backspace(line.word().length());
+                }
+                buf.write(w);
+                return true;
+            }
+            if (lst == CompletionType.Expand) {
+                return false;
+            } else {
+                lst = CompletionType.Complete;
+            }
+        }
+
+        boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE);
+        int errors = getInt(ERRORS, DEFAULT_ERRORS);
+
+        // Build a list of sorted candidates
+        Map<String, List<Candidate>> sortedCandidates = new HashMap<>();
+        for (Candidate cand : candidates) {
+            sortedCandidates
+                    .computeIfAbsent(AttributedString.fromAnsi(cand.value()).toString(), s -> new ArrayList<>())
+                    .add(cand);
+        }
+
+        // Find matchers
+        // TODO: glob completion
+        List<Function<Map<String, List<Candidate>>,
+                      Map<String, List<Candidate>>>> matchers;
+        Predicate<String> exact;
+        if (prefix) {
+            String wd = line.word();
+            String wdi = caseInsensitive ? wd.toLowerCase() : wd;
+            String wp = wdi.substring(0, line.wordCursor());
+            matchers = Arrays.asList(
+                    simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)),
+                    simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp)),
+                    typoMatcher(wp, errors, caseInsensitive)
+            );
+            exact = s -> caseInsensitive ? s.equalsIgnoreCase(wp) : s.equals(wp);
+        } else if (isSet(Option.COMPLETE_IN_WORD)) {
+            String wd = line.word();
+            String wdi = caseInsensitive ? wd.toLowerCase() : wd;
+            String wp = wdi.substring(0, line.wordCursor());
+            String ws = wdi.substring(line.wordCursor());
+            Pattern p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
+            Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*");
+            matchers = Arrays.asList(
+                    simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()),
+                    simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches()),
+                    typoMatcher(wdi, errors, caseInsensitive)
+            );
+            exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd);
+        } else {
+            String wd = line.word();
+            String wdi = caseInsensitive ? wd.toLowerCase() : wd;
+            matchers = Arrays.asList(
+                    simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)),
+                    simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi)),
+                    typoMatcher(wdi, errors, caseInsensitive)
+            );
+            exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd);
+        }
+        // Find matching candidates
+        Map<String, List<Candidate>> matching = Collections.emptyMap();
+        for (Function<Map<String, List<Candidate>>,
+                      Map<String, List<Candidate>>> matcher : matchers) {
+            matching = matcher.apply(sortedCandidates);
+            if (!matching.isEmpty()) {
+                break;
+            }
+        }
+
+        // If we have no matches, bail out
+        if (matching.isEmpty()) {
+            return false;
+        }
+
+        // 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());
+
+        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()) {
+                    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;
+    }
+
+    private CompletingParsedLine wrap(ParsedLine line) {
+        if (line instanceof CompletingParsedLine) {
+            return (CompletingParsedLine) line;
+        } else {
+            return new CompletingParsedLine() {
+                public String word() {
+                    return line.word();
+                }
+                public int wordCursor() {
+                    return line.wordCursor();
+                }
+                public int wordIndex() {
+                    return line.wordIndex();
+                }
+                public List<String> words() {
+                    return line.words();
+                }
+                public String line() {
+                    return line.line();
+                }
+                public int cursor() {
+                    return line.cursor();
+                }
+                public CharSequence escape(CharSequence candidate, boolean complete) {
+                    return candidate;
+                }
+                public int rawWordCursor() {
+                    return wordCursor();
+                }
+                public int rawWordLength() {
+                    return word().length();
+                }
+            };
+        }
+    }
+
+    protected Comparator<Candidate> getCandidateComparator(boolean caseInsensitive, String word) {
+        String wdi = caseInsensitive ? word.toLowerCase() : word;
+        ToIntFunction<String> wordDistance = w -> distance(wdi, caseInsensitive ? w.toLowerCase() : w);
+        return Comparator
+                .comparing(Candidate::value, Comparator.comparingInt(wordDistance))
+                .thenComparing(Candidate::value, Comparator.comparingInt(String::length))
+                .thenComparing(Comparator.naturalOrder());
+    }
+
+    protected String getOthersGroupName() {
+        return getString(OTHERS_GROUP_NAME, DEFAULT_OTHERS_GROUP_NAME);
+    }
+
+    protected String getOriginalGroupName() {
+        return getString(ORIGINAL_GROUP_NAME, DEFAULT_ORIGINAL_GROUP_NAME);
+    }
+
+
+    protected Comparator<String> getGroupComparator() {
+        return Comparator.<String>comparingInt(s -> getOthersGroupName().equals(s) ? 1 : getOriginalGroupName().equals(s) ? -1 : 0)
+                .thenComparing(String::toLowerCase, Comparator.naturalOrder());
+    }
+
+    private void mergeCandidates(List<Candidate> possible) {
+        // Merge candidates if the have the same key
+        Map<String, List<Candidate>> keyedCandidates = new HashMap<>();
+        for (Candidate candidate : possible) {
+            if (candidate.key() != null) {
+                List<Candidate> cands = keyedCandidates.computeIfAbsent(candidate.key(), s -> new ArrayList<>());
+                cands.add(candidate);
+            }
+        }
+        if (!keyedCandidates.isEmpty()) {
+            for (List<Candidate> candidates : keyedCandidates.values()) {
+                if (candidates.size() >= 1) {
+                    possible.removeAll(candidates);
+                    // Candidates with the same key are supposed to have
+                    // the same description
+                    candidates.sort(Comparator.comparing(Candidate::value));
+                    Candidate first = candidates.get(0);
+                    String disp = candidates.stream()
+                            .map(Candidate::displ)
+                            .collect(Collectors.joining(" "));
+                    possible.add(new Candidate(first.value(), disp, first.group(),
+                            first.descr(), first.suffix(), null, first.complete()));
+                }
+            }
+        }
+    }
+
+    private Function<Map<String, List<Candidate>>,
+                     Map<String, List<Candidate>>> simpleMatcher(Predicate<String> pred) {
+        return m -> m.entrySet().stream()
+                .filter(e -> pred.test(e.getKey()))
+                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+    }
+
+    private Function<Map<String, List<Candidate>>,
+                     Map<String, List<Candidate>>> typoMatcher(String word, int errors, boolean caseInsensitive) {
+        return m -> {
+            Map<String, List<Candidate>> map = m.entrySet().stream()
+                    .filter(e -> distance(word, caseInsensitive ? e.getKey() : e.getKey().toLowerCase()) < errors)
+                    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+            if (map.size() > 1) {
+                map.computeIfAbsent(word, w -> new ArrayList<>())
+                        .add(new Candidate(word, word, getOriginalGroupName(), null, null, null, false));
+            }
+            return map;
+        };
+    }
+
+    private int distance(String word, String cand) {
+        if (word.length() < cand.length()) {
+            int d1 = Levenshtein.distance(word, cand.substring(0, Math.min(cand.length(), word.length())));
+            int d2 = Levenshtein.distance(word, cand);
+            return Math.min(d1, d2);
+        } else {
+            return Levenshtein.distance(word, cand);
+        }
+    }
+
+    protected boolean nextBindingIsComplete() {
+        redisplay();
+        KeyMap<Binding> keyMap = keyMaps.get(MENU);
+        Binding operation = readBinding(getKeys(), keyMap);
+        if (operation instanceof Reference && MENU_COMPLETE.equals(((Reference) operation).name())) {
+            return true;
+        } else {
+            pushBackBinding();
+            return false;
+        }
+    }
+
+    private class MenuSupport implements Supplier<AttributedString> {
+        final List<Candidate> possible;
+        final BiFunction<CharSequence, Boolean, CharSequence> escaper;
+        int selection;
+        int topLine;
+        String word;
+        AttributedString computed;
+        int lines;
+        int columns;
+        String completed;
+
+        public MenuSupport(List<Candidate> original, String completed, BiFunction<CharSequence, Boolean, CharSequence> escaper) {
+            this.possible = new ArrayList<>();
+            this.escaper = escaper;
+            this.selection = -1;
+            this.topLine = 0;
+            this.word = "";
+            this.completed = completed;
+            computePost(original, null, possible, completed);
+            next();
+        }
+
+        public Candidate completion() {
+            return possible.get(selection);
+        }
+
+        public void next() {
+            selection = (selection + 1) % possible.size();
+            update();
+        }
+
+        public void previous() {
+            selection = (selection + possible.size() - 1) % possible.size();
+            update();
+        }
+
+        /**
+         * Move 'step' options along the major axis of the menu.<p>
+         * ie. if the menu is listing rows first, change row (up/down);
+         * otherwise move column (left/right)
+         *
+         * @param step number of options to move by
+         */
+        private void major(int step) {
+            int axis = isSet(Option.LIST_ROWS_FIRST) ? columns : lines;
+            int sel = selection + step * axis;
+            if (sel < 0) {
+                int pos = (sel + axis) % axis; // needs +axis as (-1)%x == -1
+                int remainders = possible.size() % axis;
+                sel = possible.size() - remainders + pos;
+                if (sel >= possible.size()) {
+                    sel -= axis;
+                }
+            } else if (sel >= possible.size()) {
+                sel = sel % axis;
+            }
+            selection = sel;
+            update();
+        }
+
+        /**
+         * Move 'step' options along the minor axis of the menu.<p>
+         * ie. if the menu is listing rows first, move along the row (left/right);
+         * otherwise move along the column (up/down)
+         *
+         * @param step number of options to move by
+         */
+        private void minor(int step) {
+            int axis = isSet(Option.LIST_ROWS_FIRST) ? columns : lines;
+            int row = selection % axis;
+            int options = possible.size();
+            if (selection - row + axis > options) {
+                // selection is the last row/column
+                // so there are fewer options than other rows
+                axis = options%axis;
+            }
+            selection = selection - row + ((axis + row + step) % axis);
+            update();
+        }
+
+        public void up() {
+            if (isSet(Option.LIST_ROWS_FIRST)) {
+                major(-1);
+            } else {
+                minor(-1);
+            }
+        }
+
+        public void down() {
+            if (isSet(Option.LIST_ROWS_FIRST)) {
+                major(1);
+            } else {
+                minor(1);
+            }
+        }
+
+        public void left() {
+            if (isSet(Option.LIST_ROWS_FIRST)) {
+                minor(-1);
+            } else {
+                major(-1);
+            }
+        }
+
+        public void right() {
+            if (isSet(Option.LIST_ROWS_FIRST)) {
+                minor(1);
+            } else {
+                major(1);
+            }
+        }
+
+        private void update() {
+            buf.backspace(word.length());
+            word = escaper.apply(completion().value(), true).toString();
+            buf.write(word);
+
+            // Compute displayed prompt
+            PostResult pr = computePost(possible, completion(), null, completed);
+            AttributedString text = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>());
+            int promptLines = text.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size();
+            if (pr.lines > size.getRows() - promptLines) {
+                int displayed = size.getRows() - promptLines - 1;
+                if (pr.selectedLine >= 0) {
+                    if (pr.selectedLine < topLine) {
+                        topLine = pr.selectedLine;
+                    } else if (pr.selectedLine >= topLine + displayed) {
+                        topLine = pr.selectedLine - displayed + 1;
+                    }
+                }
+                AttributedString post = pr.post;
+                if (post.length() > 0 && post.charAt(post.length() - 1) != '\n') {
+                    post = new AttributedStringBuilder(post.length() + 1)
+                            .append(post).append("\n").toAttributedString();
+                }
+                List<AttributedString> lines = post.columnSplitLength(size.getColumns(), true, display.delayLineWrap());
+                List<AttributedString> sub = new ArrayList<>(lines.subList(topLine, topLine + displayed));
+                sub.add(new AttributedStringBuilder()
+                        .style(AttributedStyle.DEFAULT.foreground(AttributedStyle.CYAN))
+                        .append("rows ")
+                        .append(Integer.toString(topLine + 1))
+                        .append(" to ")
+                        .append(Integer.toString(topLine + displayed))
+                        .append(" of ")
+                        .append(Integer.toString(lines.size()))
+                        .append("\n")
+                        .style(AttributedStyle.DEFAULT).toAttributedString());
+                computed = AttributedString.join(AttributedString.EMPTY, sub);
+            } else {
+                computed = pr.post;
+            }
+            lines = pr.lines;
+            columns = (possible.size() + lines - 1) / lines;
+        }
+
+        @Override
+        public AttributedString get() {
+            return computed;
+        }
+
+    }
+
+    protected boolean doMenu(List<Candidate> original, String completed, BiFunction<CharSequence, Boolean, CharSequence> escaper) {
+        // Reorder candidates according to display order
+        final List<Candidate> possible = new ArrayList<>();
+        boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE);
+        original.sort(getCandidateComparator(caseInsensitive, completed));
+        mergeCandidates(original);
+        computePost(original, null, possible, completed);
+
+        // Build menu support
+        MenuSupport menuSupport = new MenuSupport(original, completed, escaper);
+        post = menuSupport;
+        redisplay();
+
+        // Loop
+        KeyMap<Binding> keyMap = keyMaps.get(MENU);
+        Binding operation;
+        while ((operation = readBinding(getKeys(), keyMap)) != null) {
+            String ref = (operation instanceof Reference) ? ((Reference) operation).name() : "";
+            switch (ref) {
+                case MENU_COMPLETE:
+                    menuSupport.next();
+                    break;
+                case REVERSE_MENU_COMPLETE:
+                    menuSupport.previous();
+                    break;
+                case UP_LINE_OR_HISTORY:
+                case UP_LINE_OR_SEARCH:
+                    menuSupport.up();
+                    break;
+                case DOWN_LINE_OR_HISTORY:
+                case DOWN_LINE_OR_SEARCH:
+                    menuSupport.down();
+                    break;
+                case FORWARD_CHAR:
+                    menuSupport.right();
+                    break;
+                case BACKWARD_CHAR:
+                    menuSupport.left();
+                    break;
+                case CLEAR_SCREEN:
+                    clearScreen();
+                    break;
+                default: {
+                    Candidate completion = menuSupport.completion();
+                    if (completion.suffix() != null) {
+                        String chars = getString(REMOVE_SUFFIX_CHARS, DEFAULT_REMOVE_SUFFIX_CHARS);
+                        if (SELF_INSERT.equals(ref)
+                                && chars.indexOf(getLastBinding().charAt(0)) >= 0
+                                || BACKWARD_DELETE_CHAR.equals(ref)) {
+                            buf.backspace(completion.suffix().length());
+                        }
+                    }
+                    if (completion.complete()
+                            && getLastBinding().charAt(0) != ' '
+                            && (SELF_INSERT.equals(ref) || getLastBinding().charAt(0) != ' ')) {
+                        buf.write(' ');
+                    }
+                    if (!ACCEPT_LINE.equals(ref)
+                            && !(SELF_INSERT.equals(ref)
+                                && completion.suffix() != null
+                                && completion.suffix().startsWith(getLastBinding()))) {
+                        pushBackBinding(true);
+                    }
+                    post = null;
+                    return true;
+                }
+            }
+            redisplay();
+        }
+        return false;
+    }
+
+    protected boolean doList(List<Candidate> possible, String completed, boolean runLoop, BiFunction<CharSequence, Boolean, CharSequence> escaper) {
+        // If we list only and if there's a big
+        // number of items, we should ask the user
+        // for confirmation, display the list
+        // and redraw the line at the bottom
+        mergeCandidates(possible);
+        AttributedString text = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>());
+        int promptLines = text.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size();
+        PostResult postResult = computePost(possible, null, null, completed);
+        int lines = postResult.lines;
+        int listMax = getInt(LIST_MAX, DEFAULT_LIST_MAX);
+        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()
+                    + " possibilities (" + lines + " lines)?");
+            redisplay(true);
+            int c = readCharacter();
+            if (c != 'y' && c != 'Y' && c != '\t') {
+                post = null;
+                return false;
+            }
+        }
+
+        boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE);
+        StringBuilder sb = new StringBuilder();
+        while (true) {
+            String current = completed + sb.toString();
+            List<Candidate> cands;
+            if (sb.length() > 0) {
+                cands = possible.stream()
+                        .filter(c -> caseInsensitive
+                                    ? c.value().toLowerCase().startsWith(current.toLowerCase())
+                                    : c.value().startsWith(current))
+                        .sorted(getCandidateComparator(caseInsensitive, current))
+                        .collect(Collectors.toList());
+            } else {
+                cands = possible.stream()
+                        .sorted(getCandidateComparator(caseInsensitive, current))
+                        .collect(Collectors.toList());
+            }
+            post = () -> {
+                AttributedString t = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>());
+                int pl = t.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size();
+                PostResult pr = computePost(cands, null, null, current);
+                if (pr.lines >= size.getRows() - pl) {
+                    post = null;
+                    int oldCursor = buf.cursor();
+                    buf.cursor(buf.length());
+                    redisplay(false);
+                    buf.cursor(oldCursor);
+                    println();
+                    List<AttributedString> ls = postResult.post.columnSplitLength(size.getColumns(), false, display.delayLineWrap());
+                    Display d = new Display(terminal, false);
+                    d.resize(size.getRows(), size.getColumns());
+                    d.update(ls, -1);
+                    redrawLine();
+                    return new AttributedString("");
+                }
+                return pr.post;
+            };
+            if (!runLoop) {
+                return false;
+            }
+            redisplay();
+            // TODO: use a different keyMap ?
+            Binding b = bindingReader.readBinding(getKeys());
+            if (b instanceof Reference) {
+                String name = ((Reference) b).name();
+                if (BACKWARD_DELETE_CHAR.equals(name) || VI_BACKWARD_DELETE_CHAR.equals(name)) {
+                    if (sb.length() == 0) {
+                        pushBackBinding();
+                        post = null;
+                        return false;
+                    } else {
+                        sb.setLength(sb.length() - 1);
+                        buf.backspace();
+                    }
+                } else if (SELF_INSERT.equals(name)) {
+                    sb.append(getLastBinding());
+                    buf.write(getLastBinding());
+                    if (cands.isEmpty()) {
+                        post = null;
+                        return false;
+                    }
+                } else if ("\t".equals(getLastBinding())) {
+                    if (cands.size() == 1 || sb.length() > 0) {
+                        post = null;
+                        pushBackBinding();
+                    } else if (isSet(Option.AUTO_MENU)) {
+                        buf.backspace(escaper.apply(current, false).length());
+                        doMenu(cands, current, escaper);
+                    }
+                    return false;
+                } else {
+                    pushBackBinding();
+                    post = null;
+                    return false;
+                }
+            } else if (b == null) {
+                post = null;
+                return false;
+            }
+        }
+    }
+
+    protected static class PostResult {
+        final AttributedString post;
+        final int lines;
+        final int selectedLine;
+
+        public PostResult(AttributedString post, int lines, int selectedLine) {
+            this.post = post;
+            this.lines = lines;
+            this.selectedLine = selectedLine;
+        }
+    }
+
+    protected PostResult computePost(List<Candidate> possible, Candidate selection, List<Candidate> ordered, String completed) {
+        return computePost(possible, selection, ordered, completed, display::wcwidth, size.getColumns(), isSet(Option.AUTO_GROUP), isSet(Option.GROUP), isSet(Option.LIST_ROWS_FIRST));
+    }
+
+    protected PostResult computePost(List<Candidate> possible, Candidate selection, List<Candidate> ordered, String completed, Function<String, Integer> wcwidth, int width, boolean autoGroup, boolean groupName, boolean rowsFirst) {
+        List<Object> strings = new ArrayList<>();
+        if (groupName) {
+            Comparator<String> groupComparator = getGroupComparator();
+            Map<String, Map<String, Candidate>> sorted;
+            sorted = groupComparator != null
+                        ? new TreeMap<>(groupComparator)
+                        : new LinkedHashMap<>();
+            for (Candidate cand : possible) {
+                String group = cand.group();
+                sorted.computeIfAbsent(group != null ? group : "", s -> new LinkedHashMap<>())
+                        .put(cand.value(), cand);
+            }
+            for (Map.Entry<String, Map<String, Candidate>> entry : sorted.entrySet()) {
+                String group = entry.getKey();
+                if (group.isEmpty() && sorted.size() > 1) {
+                    group = getOthersGroupName();
+                }
+                if (!group.isEmpty() && autoGroup) {
+                    strings.add(group);
+                }
+                strings.add(new ArrayList<>(entry.getValue().values()));
+                if (ordered != null) {
+                    ordered.addAll(entry.getValue().values());
+                }
+            }
+        } else {
+            Set<String> groups = new LinkedHashSet<>();
+            TreeMap<String, Candidate> sorted = new TreeMap<>();
+            for (Candidate cand : possible) {
+                String group = cand.group();
+                if (group != null) {
+                    groups.add(group);
+                }
+                sorted.put(cand.value(), cand);
+            }
+            if (autoGroup) {
+                strings.addAll(groups);
+            }
+            strings.add(new ArrayList<>(sorted.values()));
+            if (ordered != null) {
+                ordered.addAll(sorted.values());
+            }
+        }
+        return toColumns(strings, selection, completed, wcwidth, width, rowsFirst);
+    }
+
+    private static final String DESC_PREFIX = "(";
+    private static final String DESC_SUFFIX = ")";
+    private static final int MARGIN_BETWEEN_DISPLAY_AND_DESC = 1;
+    private static final int MARGIN_BETWEEN_COLUMNS = 3;
+
+    @SuppressWarnings("unchecked")
+    protected PostResult toColumns(List<Object> items, Candidate selection, String completed, Function<String, Integer> wcwidth, int width, boolean rowsFirst) {
+        int[] out = new int[2];
+        // TODO: support Option.LIST_PACKED
+        // Compute column width
+        int maxWidth = 0;
+        for (Object item : items) {
+            if (item instanceof String) {
+                int len = wcwidth.apply((String) item);
+                maxWidth = Math.max(maxWidth, len);
+            }
+            else if (item instanceof List) {
+                for (Candidate cand : (List<Candidate>) item) {
+                    int len = wcwidth.apply(cand.displ());
+                    if (cand.descr() != null) {
+                        len += MARGIN_BETWEEN_DISPLAY_AND_DESC;
+                        len += DESC_PREFIX.length();
+                        len += wcwidth.apply(cand.descr());
+                        len += DESC_SUFFIX.length();
+                    }
+                    maxWidth = Math.max(maxWidth, len);
+                }
+            }
+        }
+        // Build columns
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        for (Object list : items) {
+            toColumns(list, width, maxWidth, sb, selection, completed, rowsFirst, out);
+        }
+        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\n') {
+            sb.setLength(sb.length() - 1);
+        }
+        return new PostResult(sb.toAttributedString(), out[0], out[1]);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void toColumns(Object items, int width, int maxWidth, AttributedStringBuilder sb, Candidate selection, String completed, boolean rowsFirst, int[] out) {
+        if (maxWidth <= 0) {
+            return;
+        }
+        // This is a group
+        if (items instanceof String) {
+            sb.style(getCompletionStyleGroup())
+                    .append((String) items)
+                    .style(AttributedStyle.DEFAULT)
+                    .append("\n");
+            out[0]++;
+        }
+        // This is a Candidate list
+        else if (items instanceof List) {
+            List<Candidate> candidates = (List<Candidate>) items;
+            maxWidth = Math.min(width, maxWidth);
+            int c = width / maxWidth;
+            while (c > 1 && c * maxWidth + (c - 1) * MARGIN_BETWEEN_COLUMNS >= width) {
+                c--;
+            }
+            int lines = (candidates.size() + c - 1) / c;
+            // Try to minimize the number of columns for the given number of rows
+            // Prevents eg 9 candiates being split 6/3 instead of 5/4.
+            final int columns = (candidates.size() + lines - 1) / lines;
+            IntBinaryOperator index;
+            if (rowsFirst) {
+                index = (i, j) -> i * columns + j;
+            } else {
+                index = (i, j) -> j * lines + i;
+            }
+            for (int i = 0; i < lines; i++) {
+                for (int j = 0; j < columns; j++) {
+                    int idx = index.applyAsInt(i, j);
+                    if (idx < candidates.size()) {
+                        Candidate cand = candidates.get(idx);
+                        boolean hasRightItem = j < columns - 1 && index.applyAsInt(i, j + 1) < candidates.size();
+                        AttributedString left = AttributedString.fromAnsi(cand.displ());
+                        AttributedString right = AttributedString.fromAnsi(cand.descr());
+                        int lw = left.columnLength();
+                        int rw = 0;
+                        if (right != null) {
+                            int rem = maxWidth - (lw + MARGIN_BETWEEN_DISPLAY_AND_DESC
+                                    + DESC_PREFIX.length() + DESC_SUFFIX.length());
+                            rw = right.columnLength();
+                            if (rw > rem) {
+                                right = AttributedStringBuilder.append(
+                                            right.columnSubSequence(0, rem - WCWidth.wcwidth('\u2026')),
+                                            "\u2026");
+                                rw = right.columnLength();
+                            }
+                            right = AttributedStringBuilder.append(DESC_PREFIX, right, DESC_SUFFIX);
+                            rw += DESC_PREFIX.length() + DESC_SUFFIX.length();
+                        }
+                        if (cand == selection) {
+                            out[1] = i;
+                            sb.style(getCompletionStyleSelection());
+                            if (left.toString().regionMatches(
+                                    isSet(Option.CASE_INSENSITIVE), 0, completed, 0, completed.length())) {
+                                sb.append(left.toString(), 0, completed.length());
+                                sb.append(left.toString(), completed.length(), left.length());
+                            } else {
+                                sb.append(left.toString());
+                            }
+                            for (int k = 0; k < maxWidth - lw - rw; k++) {
+                                sb.append(' ');
+                            }
+                            if (right != null) {
+                                sb.append(right);
+                            }
+                            sb.style(AttributedStyle.DEFAULT);
+                        } else {
+                            if (left.toString().regionMatches(
+                                    isSet(Option.CASE_INSENSITIVE), 0, completed, 0, completed.length())) {
+                                sb.style(getCompletionStyleStarting());
+                                sb.append(left, 0, completed.length());
+                                sb.style(AttributedStyle.DEFAULT);
+                                sb.append(left, completed.length(), left.length());
+                            } else {
+                                sb.append(left);
+                            }
+                            if (right != null || hasRightItem) {
+                                for (int k = 0; k < maxWidth - lw - rw; k++) {
+                                    sb.append(' ');
+                                }
+                            }
+                            if (right != null) {
+                                sb.style(getCompletionStyleDescription());
+                                sb.append(right);
+                                sb.style(AttributedStyle.DEFAULT);
+                            }
+                        }
+                        if (hasRightItem) {
+                            for (int k = 0; k < MARGIN_BETWEEN_COLUMNS; k++) {
+                                sb.append(' ');
+                            }
+                        }
+                    }
+                }
+                sb.append('\n');
+            }
+            out[0] += lines;
+        }
+    }
+
+    private AttributedStyle getCompletionStyleStarting() {
+        return getCompletionStyle(COMPLETION_STYLE_STARTING, DEFAULT_COMPLETION_STYLE_STARTING);
+    }
+
+    protected AttributedStyle getCompletionStyleDescription() {
+        return getCompletionStyle(COMPLETION_STYLE_DESCRIPTION, DEFAULT_COMPLETION_STYLE_DESCRIPTION);
+    }
+
+    protected AttributedStyle getCompletionStyleGroup() {
+        return getCompletionStyle(COMPLETION_STYLE_GROUP, DEFAULT_COMPLETION_STYLE_GROUP);
+    }
+
+    protected AttributedStyle getCompletionStyleSelection() {
+        return getCompletionStyle(COMPLETION_STYLE_SELECTION, DEFAULT_COMPLETION_STYLE_SELECTION);
+    }
+
+    protected AttributedStyle getCompletionStyle(String name, String value) {
+        return buildStyle(getString(name, value));
+    }
+
+    protected AttributedStyle buildStyle(String str) {
+        return AttributedString.fromAnsi("\u001b[" + str + "m ").styleAt(0);
+    }
+
+    private String getCommonStart(String str1, String str2, boolean caseInsensitive) {
+        int[] s1 = str1.codePoints().toArray();
+        int[] s2 = str2.codePoints().toArray();
+        int len = 0;
+        while (len < Math.min(s1.length, s2.length)) {
+            int ch1 = s1[len];
+            int ch2 = s2[len];
+            if (ch1 != ch2 && caseInsensitive) {
+                ch1 = Character.toUpperCase(ch1);
+                ch2 = Character.toUpperCase(ch2);
+                if (ch1 != ch2) {
+                    ch1 = Character.toLowerCase(ch1);
+                    ch2 = Character.toLowerCase(ch2);
+                }
+            }
+            if (ch1 != ch2) {
+                break;
+            }
+            len++;
+        }
+        return new String(s1, 0, len);
+    }
+
+    /**
+     * Used in "vi" mode for argumented history move, to move a specific
+     * number of history entries forward or back.
+     *
+     * @param next If true, move forward
+     * @param count The number of entries to move
+     * @return true if the move was successful
+     */
+    protected boolean moveHistory(final boolean next, int count) {
+        boolean ok = true;
+        for (int i = 0; i < count && (ok = moveHistory(next)); i++) {
+            /* empty */
+        }
+        return ok;
+    }
+
+    /**
+     * Move up or down the history tree.
+     * @param next <code>true</code> to go to the next, <code>false</code> for the previous.
+     * @return <code>true</code> if successful, <code>false</code> otherwise
+     */
+    protected boolean moveHistory(final boolean next) {
+        if (!buf.toString().equals(history.current())) {
+            modifiedHistory.put(history.index(), buf.toString());
+        }
+        if (next && !history.next()) {
+            return false;
+        }
+        else if (!next && !history.previous()) {
+            return false;
+        }
+
+        setBuffer(modifiedHistory.containsKey(history.index())
+                    ? modifiedHistory.get(history.index())
+                    : history.current());
+
+        return true;
+    }
+
+    //
+    // Printing
+    //
+
+    /**
+     * Raw output printing.
+     * @param str the string to print to the terminal
+     */
+    void print(String str) {
+        terminal.writer().write(str);
+    }
+
+    void println(String s) {
+        print(s);
+        println();
+    }
+
+    /**
+     * Output a platform-dependant newline.
+     */
+    void println() {
+        terminal.puts(Capability.carriage_return);
+        print("\n");
+        redrawLine();
+    }
+
+
+    //
+    // Actions
+    //
+
+    protected boolean killBuffer() {
+        killRing.add(buf.toString());
+        buf.clear();
+        return true;
+    }
+
+    protected boolean killWholeLine() {
+        if (buf.length() == 0) {
+            return false;
+        }
+        int start;
+        int end;
+        if (count < 0) {
+            end = buf.cursor();
+            while (buf.atChar(end) != 0 && buf.atChar(end) != '\n') {
+                end++;
+            }
+            start = end;
+            for (int count = -this.count; count > 0; --count) {
+                while (start > 0 && buf.atChar(start - 1) != '\n') {
+                    start--;
+                }
+                start--;
+            }
+        } else {
+            start = buf.cursor();
+            while (start > 0 && buf.atChar(start - 1) != '\n') {
+                start--;
+            }
+            end = start;
+            while (count-- > 0) {
+                while (end < buf.length() && buf.atChar(end) != '\n') {
+                    end++;
+                }
+                end++;
+            }
+        }
+        String killed = buf.substring(start, end);
+        buf.cursor(start);
+        buf.delete(end - start);
+        killRing.add(killed);
+        return true;
+    }
+
+    /**
+     * Kill the buffer ahead of the current cursor position.
+     *
+     * @return true if successful
+     */
+    public boolean killLine() {
+        if (count < 0) {
+            return callNeg(this::backwardKillLine);
+        }
+        if (buf.cursor() == buf.length()) {
+            return false;
+        }
+        int cp = buf.cursor();
+        int len = cp;
+        while (count-- > 0) {
+            if (buf.atChar(len) == '\n') {
+                len++;
+            } else {
+                while (buf.atChar(len) != 0 && buf.atChar(len) != '\n') {
+                    len++;
+                }
+            }
+        }
+        int num = len - cp;
+        String killed = buf.substring(cp, cp + num);
+        buf.delete(num);
+        killRing.add(killed);
+        return true;
+    }
+
+    public boolean backwardKillLine() {
+        if (count < 0) {
+            return callNeg(this::killLine);
+        }
+        if (buf.cursor() == 0) {
+            return false;
+        }
+        int cp = buf.cursor();
+        int beg = cp;
+        while (count-- > 0) {
+            if (beg == 0) {
+                break;
+            }
+            if (buf.atChar(beg - 1) == '\n') {
+                beg--;
+            } else {
+                while (beg > 0 && buf.atChar(beg - 1) != 0 && buf.atChar(beg - 1) != '\n') {
+                    beg--;
+                }
+            }
+        }
+        int num = cp - beg;
+        String killed = buf.substring(cp - beg, cp);
+        buf.cursor(beg);
+        buf.delete(num);
+        killRing.add(killed);
+        return true;
+    }
+
+    public boolean killRegion() {
+        return doCopyKillRegion(true);
+    }
+
+    public boolean copyRegionAsKill() {
+        return doCopyKillRegion(false);
+    }
+
+    private boolean doCopyKillRegion(boolean kill) {
+        if (regionMark > buf.length()) {
+            regionMark = buf.length();
+        }
+        if (regionActive == RegionType.LINE) {
+            int start = regionMark;
+            int end = buf.cursor();
+            if (start < end) {
+                while (start > 0 && buf.atChar(start - 1) != '\n') {
+                    start--;
+                }
+                while (end < buf.length() - 1 && buf.atChar(end + 1) != '\n') {
+                    end++;
+                }
+                if (isInViCmdMode()) {
+                    end++;
+                }
+                killRing.add(buf.substring(start, end));
+                if (kill) {
+                    buf.backspace(end - start);
+                }
+            } else {
+                while (end > 0 && buf.atChar(end - 1) != '\n') {
+                    end--;
+                }
+                while (start < buf.length() && buf.atChar(start) != '\n') {
+                    start++;
+                }
+                if (isInViCmdMode()) {
+                    start++;
+                }
+                killRing.addBackwards(buf.substring(end, start));
+                if (kill) {
+                    buf.cursor(end);
+                    buf.delete(start - end);
+                }
+            }
+        } else if (regionMark > buf.cursor()) {
+            if (isInViCmdMode()) {
+                regionMark++;
+            }
+            killRing.add(buf.substring(buf.cursor(), regionMark));
+            if (kill) {
+                buf.delete(regionMark - buf.cursor());
+            }
+        } else {
+            if (isInViCmdMode()) {
+                buf.move(1);
+            }
+            killRing.add(buf.substring(regionMark, buf.cursor()));
+            if (kill) {
+                buf.backspace(buf.cursor() - regionMark);
+            }
+        }
+        if (kill) {
+            regionActive = RegionType.NONE;
+        }
+        return true;
+    }
+
+    public boolean yank() {
+        String yanked = killRing.yank();
+        if (yanked == null) {
+            return false;
+        } else {
+            putString(yanked);
+            return true;
+        }
+    }
+
+    public boolean yankPop() {
+        if (!killRing.lastYank()) {
+            return false;
+        }
+        String current = killRing.yank();
+        if (current == null) {
+            // This shouldn't happen.
+            return false;
+        }
+        buf.backspace(current.length());
+        String yanked = killRing.yankPop();
+        if (yanked == null) {
+            // This shouldn't happen.
+            return false;
+        }
+
+        putString(yanked);
+        return true;
+    }
+
+    public boolean mouse() {
+        MouseEvent event = readMouseEvent();
+        if (event.getType() == MouseEvent.Type.Released
+                && event.getButton() == MouseEvent.Button.Button1) {
+            StringBuilder tsb = new StringBuilder();
+            Cursor cursor = terminal.getCursorPosition(c -> tsb.append((char) c));
+            bindingReader.runMacro(tsb.toString());
+
+            List<AttributedString> secondaryPrompts = new ArrayList<>();
+            getDisplayedBufferWithPrompts(secondaryPrompts);
+
+            AttributedStringBuilder sb = new AttributedStringBuilder().tabs(TAB_WIDTH);
+            sb.append(prompt);
+            sb.append(insertSecondaryPrompts(new AttributedString(buf.upToCursor()), secondaryPrompts, false));
+            List<AttributedString> promptLines = sb.columnSplitLength(size.getColumns(), false, display.delayLineWrap());
+
+            int currentLine = promptLines.size() - 1;
+            int wantedLine = Math.max(0, Math.min(currentLine + event.getY() - cursor.getY(), secondaryPrompts.size()));
+            int pl0 = currentLine == 0 ? prompt.columnLength() : secondaryPrompts.get(currentLine - 1).columnLength();
+            int pl1 = wantedLine == 0 ? prompt.columnLength() : secondaryPrompts.get(wantedLine - 1).columnLength();
+            int adjust = pl1 - pl0;
+            buf.moveXY(event.getX() - cursor.getX() - adjust, event.getY() - cursor.getY());
+        }
+        return true;
+    }
+
+    public boolean beginPaste() {
+        final Object SELF_INSERT = new Object();
+        final Object END_PASTE = new Object();
+        KeyMap<Object> keyMap = new KeyMap<>();
+        keyMap.setUnicode(SELF_INSERT);
+        keyMap.setNomatch(SELF_INSERT);
+        keyMap.setAmbiguousTimeout(0);
+        keyMap.bind(END_PASTE, BRACKETED_PASTE_END);
+        StringBuilder sb = new StringBuilder();
+        while (true) {
+            Object b = bindingReader.readBinding(keyMap);
+            if (b == END_PASTE) {
+                break;
+            }
+            String s = getLastBinding();
+            if ("\r".equals(s)) {
+                s = "\n";
+            }
+            sb.append(s);
+        }
+        regionActive = RegionType.PASTE;
+        regionMark = getBuffer().cursor();
+        getBuffer().write(sb);
+        return true;
+    }
+
+    public boolean focusIn() {
+        return false;
+    }
+
+    public boolean focusOut() {
+        return false;
+    }
+
+    /**
+     * Clean the used display
+     * @return <code>true</code>
+     */
+    public boolean clear() {
+        display.update(Collections.emptyList(), 0);
+        return true;
+    }
+
+    /**
+     * Clear the screen by issuing the ANSI "clear screen" code.
+     * @return <code>true</code>
+     */
+    public boolean clearScreen() {
+        if (terminal.puts(Capability.clear_screen)) {
+            Status status = Status.getStatus(terminal, false);
+            if (status != null) {
+                status.reset();
+            }
+            redrawLine();
+        } else {
+            println();
+        }
+        return true;
+    }
+
+    /**
+     * Issue an audible keyboard bell.
+     * @return <code>true</code>
+     */
+    public boolean beep() {
+        BellType bell_preference = BellType.AUDIBLE;
+        switch (getString(BELL_STYLE, DEFAULT_BELL_STYLE).toLowerCase()) {
+            case "none":
+            case "off":
+                bell_preference = BellType.NONE;
+                break;
+            case "audible":
+                bell_preference = BellType.AUDIBLE;
+                break;
+            case "visible":
+                bell_preference = BellType.VISIBLE;
+                break;
+            case "on":
+                bell_preference = getBoolean(PREFER_VISIBLE_BELL, false)
+                        ? BellType.VISIBLE : BellType.AUDIBLE;
+                break;
+        }
+        if (bell_preference == BellType.VISIBLE) {
+            if (terminal.puts(Capability.flash_screen)
+                    || terminal.puts(Capability.bell)) {
+                flush();
+            }
+        } else if (bell_preference == BellType.AUDIBLE) {
+            if (terminal.puts(Capability.bell)) {
+                flush();
+            }
+        }
+        return true;
+    }
+
+    //
+    // Helpers
+    //
+
+    /**
+     * Checks to see if the specified character is a delimiter. We consider a
+     * character a delimiter if it is anything but a letter or digit.
+     *
+     * @param c     The character to test
+     * @return      True if it is a delimiter
+     */
+    protected boolean isDelimiter(int c) {
+        return !Character.isLetterOrDigit(c);
+    }
+
+    /**
+     * Checks to see if a character is a whitespace character. Currently
+     * this delegates to {@link Character#isWhitespace(char)}, however
+     * eventually it should be hooked up so that the definition of whitespace
+     * can be configured, as readline does.
+     *
+     * @param c The character to check
+     * @return true if the character is a whitespace
+     */
+    protected boolean isWhitespace(int c) {
+        return Character.isWhitespace(c);
+    }
+
+    protected boolean isViAlphaNum(int c) {
+        return c == '_' || Character.isLetterOrDigit(c);
+    }
+
+    protected boolean isAlpha(int c) {
+        return Character.isLetter(c);
+    }
+
+    protected boolean isWord(int c) {
+        String wordchars = getString(WORDCHARS, DEFAULT_WORDCHARS);
+        return Character.isLetterOrDigit(c)
+                || (c < 128 && wordchars.indexOf((char) c) >= 0);
+    }
+
+    String getString(String name, String def) {
+        return ReaderUtils.getString(this, name, def);
+    }
+
+    boolean getBoolean(String name, boolean def) {
+        return ReaderUtils.getBoolean(this, name, def);
+    }
+
+    int getInt(String name, int def) {
+        return ReaderUtils.getInt(this, name, def);
+    }
+
+    long getLong(String name, long def) {
+        return ReaderUtils.getLong(this, name, def);
+    }
+
+    @Override
+    public Map<String, KeyMap<Binding>> defaultKeyMaps() {
+        Map<String, KeyMap<Binding>> keyMaps = new HashMap<>();
+        keyMaps.put(EMACS, emacs());
+        keyMaps.put(VICMD, viCmd());
+        keyMaps.put(VIINS, viInsertion());
+        keyMaps.put(MENU, menu());
+        keyMaps.put(VIOPP, viOpp());
+        keyMaps.put(VISUAL, visual());
+        keyMaps.put(SAFE, safe());
+        if (getBoolean(BIND_TTY_SPECIAL_CHARS, true)) {
+            Attributes attr = terminal.getAttributes();
+            bindConsoleChars(keyMaps.get(EMACS), attr);
+            bindConsoleChars(keyMaps.get(VIINS), attr);
+        }
+        // Put default
+        for (KeyMap<Binding> keyMap : keyMaps.values()) {
+            keyMap.setUnicode(new Reference(SELF_INSERT));
+            keyMap.setAmbiguousTimeout(getLong(AMBIGUOUS_BINDING, DEFAULT_AMBIGUOUS_BINDING));
+        }
+        // By default, link main to emacs
+        keyMaps.put(MAIN, keyMaps.get(EMACS));
+        return keyMaps;
+    }
+
+    public KeyMap<Binding> emacs() {
+        KeyMap<Binding> emacs = new KeyMap<>();
+        bind(emacs, SET_MARK_COMMAND,                       ctrl('@'));
+        bind(emacs, BEGINNING_OF_LINE,                      ctrl('A'));
+        bind(emacs, BACKWARD_CHAR,                          ctrl('B'));
+        bind(emacs, DELETE_CHAR_OR_LIST,                    ctrl('D'));
+        bind(emacs, END_OF_LINE,                            ctrl('E'));
+        bind(emacs, FORWARD_CHAR,                           ctrl('F'));
+        bind(emacs, SEND_BREAK,                             ctrl('G'));
+        bind(emacs, BACKWARD_DELETE_CHAR,                   ctrl('H'));
+        bind(emacs, EXPAND_OR_COMPLETE,                     ctrl('I'));
+        bind(emacs, ACCEPT_LINE,                            ctrl('J'));
+        bind(emacs, KILL_LINE,                              ctrl('K'));
+        bind(emacs, CLEAR_SCREEN,                           ctrl('L'));
+        bind(emacs, ACCEPT_LINE,                            ctrl('M'));
+        bind(emacs, DOWN_LINE_OR_HISTORY,                   ctrl('N'));
+        bind(emacs, UP_LINE_OR_HISTORY,                     ctrl('P'));
+        bind(emacs, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('R'));
+        bind(emacs, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('S'));
+        bind(emacs, TRANSPOSE_CHARS,                        ctrl('T'));
+        bind(emacs, KILL_WHOLE_LINE,                        ctrl('U'));
+        bind(emacs, QUOTED_INSERT,                          ctrl('V'));
+        bind(emacs, BACKWARD_KILL_WORD,                     ctrl('W'));
+        bind(emacs, YANK,                                   ctrl('Y'));
+        bind(emacs, CHARACTER_SEARCH,                       ctrl(']'));
+        bind(emacs, UNDO,                                   ctrl('_'));
+        bind(emacs, SELF_INSERT,                            range(" -~"));
+        bind(emacs, INSERT_CLOSE_PAREN,                     ")");
+        bind(emacs, INSERT_CLOSE_SQUARE,                    "]");
+        bind(emacs, INSERT_CLOSE_CURLY,                     "}");
+        bind(emacs, BACKWARD_DELETE_CHAR,                   del());
+        bind(emacs, VI_MATCH_BRACKET,                       translate("^X^B"));
+        bind(emacs, SEND_BREAK,                             translate("^X^G"));
+        bind(emacs, VI_FIND_NEXT_CHAR,                      translate("^X^F"));
+        bind(emacs, VI_JOIN,                                translate("^X^J"));
+        bind(emacs, KILL_BUFFER,                            translate("^X^K"));
+        bind(emacs, INFER_NEXT_HISTORY,                     translate("^X^N"));
+        bind(emacs, OVERWRITE_MODE,                         translate("^X^O"));
+        bind(emacs, REDO,                                   translate("^X^R"));
+        bind(emacs, UNDO,                                   translate("^X^U"));
+        bind(emacs, VI_CMD_MODE,                            translate("^X^V"));
+        bind(emacs, EXCHANGE_POINT_AND_MARK,                translate("^X^X"));
+        bind(emacs, DO_LOWERCASE_VERSION,                   translate("^XA-^XZ"));
+        bind(emacs, WHAT_CURSOR_POSITION,                   translate("^X="));
+        bind(emacs, KILL_LINE,                              translate("^X^?"));
+        bind(emacs, SEND_BREAK,                             alt(ctrl('G')));
+        bind(emacs, BACKWARD_KILL_WORD,                     alt(ctrl('H')));
+        bind(emacs, SELF_INSERT_UNMETA,                     alt(ctrl('M')));
+        bind(emacs, COMPLETE_WORD,                          alt(esc()));
+        bind(emacs, CHARACTER_SEARCH_BACKWARD,              alt(ctrl(']')));
+        bind(emacs, COPY_PREV_WORD,                         alt(ctrl('_')));
+        bind(emacs, SET_MARK_COMMAND,                       alt(' '));
+        bind(emacs, NEG_ARGUMENT,                           alt('-'));
+        bind(emacs, DIGIT_ARGUMENT,                         range("\\E0-\\E9"));
+        bind(emacs, BEGINNING_OF_HISTORY,                   alt('<'));
+        bind(emacs, LIST_CHOICES,                           alt('='));
+        bind(emacs, END_OF_HISTORY,                         alt('>'));
+        bind(emacs, LIST_CHOICES,                           alt('?'));
+        bind(emacs, DO_LOWERCASE_VERSION,                   range("^[A-^[Z"));
+        bind(emacs, BACKWARD_WORD,                          alt('b'));
+        bind(emacs, CAPITALIZE_WORD,                        alt('c'));
+        bind(emacs, KILL_WORD,                              alt('d'));
+        bind(emacs, KILL_WORD,                              translate("^[[3;5~")); // ctrl-delete
+        bind(emacs, FORWARD_WORD,                           alt('f'));
+        bind(emacs, DOWN_CASE_WORD,                         alt('l'));
+        bind(emacs, HISTORY_SEARCH_FORWARD,                 alt('n'));
+        bind(emacs, HISTORY_SEARCH_BACKWARD,                alt('p'));
+        bind(emacs, TRANSPOSE_WORDS,                        alt('t'));
+        bind(emacs, UP_CASE_WORD,                           alt('u'));
+        bind(emacs, YANK_POP,                               alt('y'));
+        bind(emacs, BACKWARD_KILL_WORD,                     alt(del()));
+        bindArrowKeys(emacs);
+        bind(emacs, FORWARD_WORD,                           translate("^[[1;5C")); // ctrl-left
+        bind(emacs, BACKWARD_WORD,                          translate("^[[1;5D")); // ctrl-right
+        bind(emacs, FORWARD_WORD,                           alt(key(Capability.key_right)));
+        bind(emacs, BACKWARD_WORD,                          alt(key(Capability.key_left)));
+        bind(emacs, FORWARD_WORD,                           alt(translate("^[[C")));
+        bind(emacs, BACKWARD_WORD,                          alt(translate("^[[D")));
+        return emacs;
+    }
+
+    public KeyMap<Binding> viInsertion() {
+        KeyMap<Binding> viins = new KeyMap<>();
+        bind(viins, SELF_INSERT,                            range("^@-^_"));
+        bind(viins, LIST_CHOICES,                           ctrl('D'));
+        bind(viins, SEND_BREAK,                             ctrl('G'));
+        bind(viins, BACKWARD_DELETE_CHAR,                   ctrl('H'));
+        bind(viins, EXPAND_OR_COMPLETE,                     ctrl('I'));
+        bind(viins, ACCEPT_LINE,                            ctrl('J'));
+        bind(viins, CLEAR_SCREEN,                           ctrl('L'));
+        bind(viins, ACCEPT_LINE,                            ctrl('M'));
+        bind(viins, MENU_COMPLETE,                          ctrl('N'));
+        bind(viins, REVERSE_MENU_COMPLETE,                  ctrl('P'));
+        bind(viins, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('R'));
+        bind(viins, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('S'));
+        bind(viins, TRANSPOSE_CHARS,                        ctrl('T'));
+        bind(viins, KILL_WHOLE_LINE,                        ctrl('U'));
+        bind(viins, QUOTED_INSERT,                          ctrl('V'));
+        bind(viins, BACKWARD_KILL_WORD,                     ctrl('W'));
+        bind(viins, YANK,                                   ctrl('Y'));
+        bind(viins, VI_CMD_MODE,                            ctrl('['));
+        bind(viins, UNDO,                                   ctrl('_'));
+        bind(viins, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('X') + "r");
+        bind(viins, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('X') + "s");
+        bind(viins, SELF_INSERT,                            range(" -~"));
+        bind(viins, INSERT_CLOSE_PAREN,                     ")");
+        bind(viins, INSERT_CLOSE_SQUARE,                    "]");
+        bind(viins, INSERT_CLOSE_CURLY,                     "}");
+        bind(viins, BACKWARD_DELETE_CHAR,                   del());
+        bindArrowKeys(viins);
+        return viins;
+    }
+
+    public KeyMap<Binding> viCmd() {
+        KeyMap<Binding> vicmd = new KeyMap<>();
+        bind(vicmd, LIST_CHOICES,                           ctrl('D'));
+        bind(vicmd, EMACS_EDITING_MODE,                     ctrl('E'));
+        bind(vicmd, SEND_BREAK,                             ctrl('G'));
+        bind(vicmd, VI_BACKWARD_CHAR,                       ctrl('H'));
+        bind(vicmd, ACCEPT_LINE,                            ctrl('J'));
+        bind(vicmd, KILL_LINE,                              ctrl('K'));
+        bind(vicmd, CLEAR_SCREEN,                           ctrl('L'));
+        bind(vicmd, ACCEPT_LINE,                            ctrl('M'));
+        bind(vicmd, VI_DOWN_LINE_OR_HISTORY,                ctrl('N'));
+        bind(vicmd, VI_UP_LINE_OR_HISTORY,                  ctrl('P'));
+        bind(vicmd, QUOTED_INSERT,                          ctrl('Q'));
+        bind(vicmd, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('R'));
+        bind(vicmd, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('S'));
+        bind(vicmd, TRANSPOSE_CHARS,                        ctrl('T'));
+        bind(vicmd, KILL_WHOLE_LINE,                        ctrl('U'));
+        bind(vicmd, QUOTED_INSERT,                          ctrl('V'));
+        bind(vicmd, BACKWARD_KILL_WORD,                     ctrl('W'));
+        bind(vicmd, YANK,                                   ctrl('Y'));
+        bind(vicmd, HISTORY_INCREMENTAL_SEARCH_BACKWARD,    ctrl('X') + "r");
+        bind(vicmd, HISTORY_INCREMENTAL_SEARCH_FORWARD,     ctrl('X') + "s");
+        bind(vicmd, SEND_BREAK,                             alt(ctrl('G')));
+        bind(vicmd, BACKWARD_KILL_WORD,                     alt(ctrl('H')));
+        bind(vicmd, SELF_INSERT_UNMETA,                     alt(ctrl('M')));
+        bind(vicmd, COMPLETE_WORD,                          alt(esc()));
+        bind(vicmd, CHARACTER_SEARCH_BACKWARD,              alt(ctrl(']')));
+        bind(vicmd, SET_MARK_COMMAND,                       alt(' '));
+//        bind(vicmd, INSERT_COMMENT,                         alt('#'));
+//        bind(vicmd, INSERT_COMPLETIONS,                     alt('*'));
+        bind(vicmd, DIGIT_ARGUMENT,                         alt('-'));
+        bind(vicmd, BEGINNING_OF_HISTORY,                   alt('<'));
+        bind(vicmd, LIST_CHOICES,                           alt('='));
+        bind(vicmd, END_OF_HISTORY,                         alt('>'));
+        bind(vicmd, LIST_CHOICES,                           alt('?'));
+        bind(vicmd, DO_LOWERCASE_VERSION,                   range("^[A-^[Z"));
+        bind(vicmd, BACKWARD_WORD,                          alt('b'));
+        bind(vicmd, CAPITALIZE_WORD,                        alt('c'));
+        bind(vicmd, KILL_WORD,                              alt('d'));
+        bind(vicmd, FORWARD_WORD,                           alt('f'));
+        bind(vicmd, DOWN_CASE_WORD,                         alt('l'));
+        bind(vicmd, HISTORY_SEARCH_FORWARD,                 alt('n'));
+        bind(vicmd, HISTORY_SEARCH_BACKWARD,                alt('p'));
+        bind(vicmd, TRANSPOSE_WORDS,                        alt('t'));
+        bind(vicmd, UP_CASE_WORD,                           alt('u'));
+        bind(vicmd, YANK_POP,                               alt('y'));
+        bind(vicmd, BACKWARD_KILL_WORD,                     alt(del()));
+
+        bind(vicmd, FORWARD_CHAR,                           " ");
+        bind(vicmd, VI_INSERT_COMMENT,                      "#");
+        bind(vicmd, END_OF_LINE,                            "$");
+        bind(vicmd, VI_MATCH_BRACKET,                       "%");
+        bind(vicmd, VI_DOWN_LINE_OR_HISTORY,                "+");
+        bind(vicmd, VI_REV_REPEAT_FIND,                     ",");
+        bind(vicmd, VI_UP_LINE_OR_HISTORY,                  "-");
+        bind(vicmd, VI_REPEAT_CHANGE,                       ".");
+        bind(vicmd, VI_HISTORY_SEARCH_BACKWARD,             "/");
+        bind(vicmd, VI_DIGIT_OR_BEGINNING_OF_LINE,          "0");
+        bind(vicmd, DIGIT_ARGUMENT,                         range("1-9"));
+        bind(vicmd, VI_REPEAT_FIND,                         ";");
+        bind(vicmd, LIST_CHOICES,                           "=");
+        bind(vicmd, VI_HISTORY_SEARCH_FORWARD,              "?");
+        bind(vicmd, VI_ADD_EOL,                             "A");
+        bind(vicmd, VI_BACKWARD_BLANK_WORD,                 "B");
+        bind(vicmd, VI_CHANGE_EOL,                          "C");
+        bind(vicmd, VI_KILL_EOL,                            "D");
+        bind(vicmd, VI_FORWARD_BLANK_WORD_END,              "E");
+        bind(vicmd, VI_FIND_PREV_CHAR,                      "F");
+        bind(vicmd, VI_FETCH_HISTORY,                       "G");
+        bind(vicmd, VI_INSERT_BOL,                          "I");
+        bind(vicmd, VI_JOIN,                                "J");
+        bind(vicmd, VI_REV_REPEAT_SEARCH,                   "N");
+        bind(vicmd, VI_OPEN_LINE_ABOVE,                     "O");
+        bind(vicmd, VI_PUT_BEFORE,                          "P");
+        bind(vicmd, VI_REPLACE,                             "R");
+        bind(vicmd, VI_KILL_LINE,                           "S");
+        bind(vicmd, VI_FIND_PREV_CHAR_SKIP,                 "T");
+        bind(vicmd, REDO,                                   "U");
+        bind(vicmd, VISUAL_LINE_MODE,                       "V");
+        bind(vicmd, VI_FORWARD_BLANK_WORD,                  "W");
+        bind(vicmd, VI_BACKWARD_DELETE_CHAR,                "X");
+        bind(vicmd, VI_YANK_WHOLE_LINE,                     "Y");
+        bind(vicmd, VI_FIRST_NON_BLANK,                     "^");
+        bind(vicmd, VI_ADD_NEXT,                            "a");
+        bind(vicmd, VI_BACKWARD_WORD,                       "b");
+        bind(vicmd, VI_CHANGE,                              "c");
+        bind(vicmd, VI_DELETE,                              "d");
+        bind(vicmd, VI_FORWARD_WORD_END,                    "e");
+        bind(vicmd, VI_FIND_NEXT_CHAR,                      "f");
+        bind(vicmd, WHAT_CURSOR_POSITION,                   "ga");
+        bind(vicmd, VI_BACKWARD_BLANK_WORD_END,             "gE");
+        bind(vicmd, VI_BACKWARD_WORD_END,                   "ge");
+        bind(vicmd, VI_BACKWARD_CHAR,                       "h");
+        bind(vicmd, VI_INSERT,                              "i");
+        bind(vicmd, DOWN_LINE_OR_HISTORY,                   "j");
+        bind(vicmd, UP_LINE_OR_HISTORY,                     "k");
+        bind(vicmd, VI_FORWARD_CHAR,                        "l");
+        bind(vicmd, VI_REPEAT_SEARCH,                       "n");
+        bind(vicmd, VI_OPEN_LINE_BELOW,                     "o");
+        bind(vicmd, VI_PUT_AFTER,                           "p");
+        bind(vicmd, VI_REPLACE_CHARS,                       "r");
+        bind(vicmd, VI_SUBSTITUTE,                          "s");
+        bind(vicmd, VI_FIND_NEXT_CHAR_SKIP,                 "t");
+        bind(vicmd, UNDO,                                   "u");
+        bind(vicmd, VISUAL_MODE,                            "v");
+        bind(vicmd, VI_FORWARD_WORD,                        "w");
+        bind(vicmd, VI_DELETE_CHAR,                         "x");
+        bind(vicmd, VI_YANK,                                "y");
+        bind(vicmd, VI_GOTO_COLUMN,                         "|");
+        bind(vicmd, VI_SWAP_CASE,                           "~");
+        bind(vicmd, VI_BACKWARD_CHAR,                       del());
+
+        bindArrowKeys(vicmd);
+        return vicmd;
+    }
+
+    public KeyMap<Binding> menu() {
+        KeyMap<Binding> menu = new KeyMap<>();
+        bind(menu, MENU_COMPLETE,                     "\t");
+        bind(menu, REVERSE_MENU_COMPLETE,             key(Capability.back_tab));
+        bind(menu, ACCEPT_LINE,                       "\r", "\n");
+        bindArrowKeys(menu);
+        return menu;
+    }
+
+    public KeyMap<Binding> safe() {
+        KeyMap<Binding> safe = new KeyMap<>();
+        bind(safe, SELF_INSERT,                 range("^@-^?"));
+        bind(safe, ACCEPT_LINE,                 "\r", "\n");
+        bind(safe, SEND_BREAK,                  ctrl('G'));
+        return safe;
+    }
+
+    public KeyMap<Binding> visual() {
+        KeyMap<Binding> visual = new KeyMap<>();
+        bind(visual, UP_LINE,                   key(Capability.key_up),     "k");
+        bind(visual, DOWN_LINE,                 key(Capability.key_down),   "j");
+        bind(visual, this::deactivateRegion,    esc());
+        bind(visual, EXCHANGE_POINT_AND_MARK,   "o");
+        bind(visual, PUT_REPLACE_SELECTION,     "p");
+        bind(visual, VI_DELETE,                 "x");
+        bind(visual, VI_OPER_SWAP_CASE,         "~");
+        return visual;
+    }
+
+    public KeyMap<Binding> viOpp() {
+        KeyMap<Binding> viOpp = new KeyMap<>();
+        bind(viOpp, UP_LINE,                    key(Capability.key_up),     "k");
+        bind(viOpp, DOWN_LINE,                  key(Capability.key_down),   "j");
+        bind(viOpp, VI_CMD_MODE,                esc());
+        return viOpp;
+    }
+
+    private void bind(KeyMap<Binding> map, String widget, Iterable<? extends CharSequence> keySeqs) {
+        map.bind(new Reference(widget), keySeqs);
+    }
+
+    private void bind(KeyMap<Binding> map, String widget, CharSequence... keySeqs) {
+        map.bind(new Reference(widget), keySeqs);
+    }
+
+    private void bind(KeyMap<Binding> map, Widget widget, CharSequence... keySeqs) {
+        map.bind(widget, keySeqs);
+    }
+
+    private String key(Capability capability) {
+        return KeyMap.key(terminal, capability);
+    }
+
+    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));
+        bind(map, BACKWARD_CHAR,        key(Capability.key_left));
+        bind(map, FORWARD_CHAR,         key(Capability.key_right));
+        bind(map, BEGINNING_OF_LINE,    key(Capability.key_home));
+        bind(map, END_OF_LINE,          key(Capability.key_end));
+        bind(map, DELETE_CHAR,          key(Capability.key_dc));
+        bind(map, KILL_WHOLE_LINE,      key(Capability.key_dl));
+        bind(map, OVERWRITE_MODE,       key(Capability.key_ic));
+        bind(map, MOUSE,                key(Capability.key_mouse));
+        bind(map, BEGIN_PASTE,          BRACKETED_PASTE_BEGIN);
+        bind(map, FOCUS_IN,             FOCUS_IN_SEQ);
+        bind(map, FOCUS_OUT,            FOCUS_OUT_SEQ);
+    }
+
+    /**
+     * Bind special chars defined by the terminal instead of
+     * the default bindings
+     */
+    private void bindConsoleChars(KeyMap<Binding> keyMap, Attributes attr) {
+        if (attr != null) {
+            rebind(keyMap, BACKWARD_DELETE_CHAR,
+                    del(), (char) attr.getControlChar(ControlChar.VERASE));
+            rebind(keyMap, BACKWARD_KILL_WORD,
+                    ctrl('W'),  (char) attr.getControlChar(ControlChar.VWERASE));
+            rebind(keyMap, KILL_WHOLE_LINE,
+                    ctrl('U'), (char) attr.getControlChar(ControlChar.VKILL));
+            rebind(keyMap, QUOTED_INSERT,
+                    ctrl('V'), (char) attr.getControlChar(ControlChar.VLNEXT));
+        }
+    }
+
+    private void rebind(KeyMap<Binding> keyMap, String operation, String prevBinding, char newBinding) {
+        if (newBinding > 0 && newBinding < 128) {
+            Reference ref = new Reference(operation);
+            bind(keyMap, SELF_INSERT, prevBinding);
+            keyMap.bind(ref, Character.toString(newBinding));
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,70 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import jdk.internal.org.jline.reader.LineReader;
+
+public class ReaderUtils {
+
+    private ReaderUtils() { }
+
+    public static boolean isSet(LineReader reader, LineReader.Option option) {
+        return reader != null && reader.isSet(option);
+    }
+
+    public static String getString(LineReader reader, String name, String def) {
+        Object v = reader != null ? reader.getVariable(name) : null;
+        return v != null ? v.toString() : def;
+    }
+
+    public static boolean getBoolean(LineReader reader, String name, boolean def) {
+        Object v = reader != null ? reader.getVariable(name) : null;
+        if (v instanceof Boolean) {
+            return (Boolean) v;
+        } else if (v != null) {
+            String s = v.toString();
+            return s.isEmpty() || s.equalsIgnoreCase("on")
+                    || s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true");
+        }
+        return def;
+    }
+
+    public static int getInt(LineReader reader, String name, int def) {
+        int nb = def;
+        Object v = reader != null ? reader.getVariable(name) : null;
+        if (v instanceof Number) {
+            return ((Number) v).intValue();
+        } else if (v != null) {
+            nb = 0;
+            try {
+                nb = Integer.parseInt(v.toString());
+            } catch (NumberFormatException e) {
+                // Ignore
+            }
+        }
+        return nb;
+    }
+
+    public static long getLong(LineReader reader, String name, long def) {
+        long nb = def;
+        Object v = reader != null ? reader.getVariable(name) : null;
+        if (v instanceof Number) {
+            return ((Number) v).longValue();
+        } else if (v != null) {
+            nb = 0;
+            try {
+                nb = Long.parseLong(v.toString());
+            } catch (NumberFormatException e) {
+                // Ignore
+            }
+        }
+        return nb;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/SimpleMaskingCallback.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import jdk.internal.org.jline.reader.MaskingCallback;
+
+import java.util.Objects;
+
+/**
+ * Simple {@link MaskingCallback} that will replace all the characters in the line with the given mask.
+ * If the given mask is equal to {@link LineReaderImpl#NULL_MASK} then the line will be replaced with an empty String.
+ */
+public final class SimpleMaskingCallback implements MaskingCallback {
+    private final Character mask;
+
+    public SimpleMaskingCallback(Character mask) {
+        this.mask = Objects.requireNonNull(mask, "mask must be a non null character");
+    }
+
+    @Override
+    public String display(String line) {
+        if (mask.equals(LineReaderImpl.NULL_MASK)) {
+            return "";
+        } else {
+            StringBuilder sb = new StringBuilder(line.length());
+            for (int i = line.length(); i-- > 0;) {
+                sb.append((char) mask);
+            }
+            return sb.toString();
+        }
+    }
+
+    @Override
+    public String history(String line) {
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/UndoTree.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,75 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl;
+
+import java.util.function.Consumer;
+
+/**
+ * Simple undo tree.
+ * Note that the first added state can't be undone
+ */
+public class UndoTree<T> {
+
+    private final Consumer<T> state;
+    private final Node parent;
+    private Node current;
+
+    public UndoTree(Consumer<T> s) {
+        state = s;
+        parent = new Node(null);
+        parent.left = parent;
+        clear();
+    }
+
+    public void clear() {
+        current = parent;
+    }
+
+    public void newState(T state) {
+        Node node = new Node(state);
+        current.right = node;
+        node.left = current;
+        current = node;
+    }
+
+    public boolean canUndo() {
+        return current.left != parent;
+    }
+
+    public boolean canRedo() {
+        return current.right != null;
+    }
+
+    public void undo() {
+        if (!canUndo()) {
+            throw new IllegalStateException("Cannot undo.");
+        }
+        current = current.left;
+        state.accept(current.state);
+    }
+
+    public void redo() {
+        if (!canRedo()) {
+            throw new IllegalStateException("Cannot redo.");
+        }
+        current = current.right;
+        state.accept(current.state);
+    }
+
+    private class Node {
+        private final T state;
+        private Node left = null;
+        private Node right = null;
+
+        public Node(T s) {
+            state = s;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/AggregateCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,86 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.ParsedLine;
+
+/**
+ * Completer which contains multiple completers and aggregates them together.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class AggregateCompleter
+    implements Completer
+{
+    private final Collection<Completer> completers;
+
+    /**
+     * Construct an AggregateCompleter with the given completers.
+     * The completers will be used in the order given.
+     *
+     * @param completers the completers
+     */
+    public AggregateCompleter(final Completer... completers) {
+        this(Arrays.asList(completers));
+    }
+
+    /**
+     * Construct an AggregateCompleter with the given completers.
+     * The completers will be used in the order given.
+     *
+     * @param completers the completers
+     */
+    public AggregateCompleter(Collection<Completer> completers) {
+        assert completers != null;
+        this.completers = completers;
+    }
+
+    /**
+     * Retrieve the collection of completers currently being aggregated.
+     *
+     * @return the aggregated completers
+     */
+    public Collection<Completer> getCompleters() {
+        return completers;
+    }
+
+    /**
+     * Perform a completion operation across all aggregated completers.
+     *
+     * The effect is similar to the following code:
+     * <blockquote><pre>{@code completers.forEach(c -> c.complete(reader, line, candidates));}</pre></blockquote>
+     *
+     * @see Completer#complete(LineReader, ParsedLine, List)
+     */
+    public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {
+        Objects.requireNonNull(line);
+        Objects.requireNonNull(candidates);
+        completers.forEach(c -> c.complete(reader, line, candidates));
+    }
+
+    /**
+     * @return a string representing the aggregated completers
+     */
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "{" +
+            "completers=" + completers +
+            '}';
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/ArgumentCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.ParsedLine;
+
+/**
+ * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
+ * This can be used instead of the individual completers having to know about argument parsing semantics.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class ArgumentCompleter implements Completer
+{
+    private final List<Completer> completers = new ArrayList<>();
+
+    private boolean strict = true;
+
+    /**
+     * Create a new completer.
+     *
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final Collection<Completer> completers) {
+        Objects.requireNonNull(completers);
+        this.completers.addAll(completers);
+    }
+
+    /**
+     * Create a new completer.
+     *
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final Completer... completers) {
+        this(Arrays.asList(completers));
+    }
+
+    /**
+     * If true, a completion at argument index N will only succeed
+     * if all the completions from 0-(N-1) also succeed.
+     *
+     * @param strict the strict flag
+     */
+    public void setStrict(final boolean strict) {
+        this.strict = strict;
+    }
+
+    /**
+     * Returns whether a completion at argument index N will success
+     * if all the completions from arguments 0-(N-1) also succeed.
+     *
+     * @return  True if strict.
+     * @since 2.3
+     */
+    public boolean isStrict() {
+        return this.strict;
+    }
+
+    /**
+     * Returns the list of completers used inside this <code>ArgumentCompleter</code>.
+     * @return The list of completers.
+     * @since 2.3
+     */
+    public List<Completer> getCompleters() {
+        return completers;
+    }
+
+    public void complete(LineReader reader, ParsedLine line, final List<Candidate> candidates) {
+        Objects.requireNonNull(line);
+        Objects.requireNonNull(candidates);
+
+        if (line.wordIndex() < 0) {
+            return;
+        }
+
+        List<Completer> completers = getCompleters();
+        Completer completer;
+
+        // if we are beyond the end of the completers, just use the last one
+        if (line.wordIndex() >= completers.size()) {
+            completer = completers.get(completers.size() - 1);
+        }
+        else {
+            completer = completers.get(line.wordIndex());
+        }
+
+        // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
+        for (int i = 0; isStrict() && (i < line.wordIndex()); i++) {
+            Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
+            List<? extends CharSequence> args = line.words();
+            String arg = (args == null || i >= args.size()) ? "" : args.get(i).toString();
+
+            List<Candidate> subCandidates = new LinkedList<>();
+            sub.complete(reader, new ArgumentLine(arg, arg.length()), subCandidates);
+
+            boolean found = false;
+            for (Candidate cand : subCandidates) {
+                if (cand.value().equals(arg)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return;
+            }
+        }
+
+        completer.complete(reader, line, candidates);
+    }
+
+    public static class ArgumentLine implements ParsedLine {
+        private final String word;
+        private final int cursor;
+
+        public ArgumentLine(String word, int cursor) {
+            this.word = word;
+            this.cursor = cursor;
+        }
+
+        @Override
+        public String word() {
+            return word;
+        }
+
+        @Override
+        public int wordCursor() {
+            return cursor;
+        }
+
+        @Override
+        public int wordIndex() {
+            return 0;
+        }
+
+        @Override
+        public List<String> words() {
+            return Collections.singletonList(word);
+        }
+
+        @Override
+        public String line() {
+            return word;
+        }
+
+        @Override
+        public int cursor() {
+            return cursor;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/EnumCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.util.Objects;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+
+/**
+ * {@link Completer} for {@link Enum} names.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class EnumCompleter extends StringsCompleter
+{
+    public EnumCompleter(Class<? extends Enum<?>> source) {
+        Objects.requireNonNull(source);
+        for (Enum<?> n : source.getEnumConstants()) {
+            candidates.add(new Candidate(n.name().toLowerCase()));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/FileNameCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.LineReader.Option;
+import jdk.internal.org.jline.reader.ParsedLine;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.AttributedStringBuilder;
+import jdk.internal.org.jline.utils.AttributedStyle;
+
+/**
+ * A file name completer takes the buffer and issues a list of
+ * potential completions.
+ * <p>
+ * This completer tries to behave as similar as possible to
+ * <i>bash</i>'s file name completion (using GNU readline)
+ * with the following exceptions:
+ * <ul>
+ * <li>Candidates that are directories will end with "/"</li>
+ * <li>Wildcard regular expressions are not evaluated or replaced</li>
+ * <li>The "~" character can be used to represent the user's home,
+ * but it cannot complete to other users' homes, since java does
+ * not provide any way of determining that easily</li>
+ * </ul>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ * @deprecated use <code>org.jline.builtins.Completers$FileNameCompleter</code> instead
+ */
+@Deprecated
+public class FileNameCompleter implements Completer
+{
+
+    public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) {
+        assert commandLine != null;
+        assert candidates != null;
+
+        String buffer = commandLine.word().substring(0, commandLine.wordCursor());
+
+        Path current;
+        String curBuf;
+        String sep = getUserDir().getFileSystem().getSeparator();
+        int lastSep = buffer.lastIndexOf(sep);
+        if (lastSep >= 0) {
+            curBuf = buffer.substring(0, lastSep + 1);
+            if (curBuf.startsWith("~")) {
+                if (curBuf.startsWith("~" + sep)) {
+                    current = getUserHome().resolve(curBuf.substring(2));
+                } else {
+                    current = getUserHome().getParent().resolve(curBuf.substring(1));
+                }
+            } else {
+                current = getUserDir().resolve(curBuf);
+            }
+        } else {
+            curBuf = "";
+            current = getUserDir();
+        }
+        try {
+            Files.newDirectoryStream(current, this::accept).forEach(p -> {
+                String value = curBuf + p.getFileName().toString();
+                if (Files.isDirectory(p)) {
+                    candidates.add(new Candidate(
+                            value + (reader.isSet(Option.AUTO_PARAM_SLASH) ? sep : ""),
+                            getDisplay(reader.getTerminal(), p),
+                            null, null,
+                            reader.isSet(Option.AUTO_REMOVE_SLASH) ? sep : null,
+                            null,
+                            false));
+                } else {
+                    candidates.add(new Candidate(value, getDisplay(reader.getTerminal(), p),
+                            null, null, null, null, true));
+                }
+            });
+        } catch (IOException e) {
+            // Ignore
+        }
+    }
+
+    protected boolean accept(Path path) {
+        try {
+            return !Files.isHidden(path);
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    protected Path getUserDir() {
+        return Paths.get(System.getProperty("user.dir"));
+    }
+
+    protected Path getUserHome() {
+        return Paths.get(System.getProperty("user.home"));
+    }
+
+    protected String getDisplay(Terminal terminal, Path p) {
+        // TODO: use $LS_COLORS for output
+        String name = p.getFileName().toString();
+        if (Files.isDirectory(p)) {
+            AttributedStringBuilder sb = new AttributedStringBuilder();
+            sb.styled(AttributedStyle.BOLD.foreground(AttributedStyle.RED), name);
+            sb.append("/");
+            name = sb.toAnsi(terminal);
+        } else if (Files.isSymbolicLink(p)) {
+            AttributedStringBuilder sb = new AttributedStringBuilder();
+            sb.styled(AttributedStyle.BOLD.foreground(AttributedStyle.RED), name);
+            sb.append("@");
+            name = sb.toAnsi(terminal);
+        }
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/NullCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.util.List;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.ParsedLine;
+
+/**
+ * Null completer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public final class NullCompleter
+    implements Completer
+{
+    public static final NullCompleter INSTANCE = new NullCompleter();
+
+    public void complete(LineReader reader, final ParsedLine line, final List<Candidate> candidates) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,52 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.reader.impl.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.ParsedLine;
+import jdk.internal.org.jline.utils.AttributedString;
+
+/**
+ * Completer for a set of strings.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class StringsCompleter implements Completer
+{
+    protected final Collection<Candidate> candidates = new ArrayList<>();
+
+    public StringsCompleter() {
+    }
+
+    public StringsCompleter(String... strings) {
+        this(Arrays.asList(strings));
+    }
+
+    public StringsCompleter(Iterable<String> strings) {
+        assert strings != null;
+        for (String string : strings) {
+            candidates.add(new Candidate(AttributedString.stripAnsi(string), string, null, null, null, null, true));
+        }
+    }
+
+    public void complete(LineReader reader, final ParsedLine commandLine, final List<Candidate> candidates) {
+        assert commandLine != null;
+        assert candidates != null;
+        candidates.addAll(this.candidates);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/package-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,14 @@
+/*
+ * 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
+ */
+/**
+ * JLine 3.
+ *
+ * @since 3.0
+ */
+package jdk.internal.org.jline.reader.impl.completer;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,507 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.reader.impl.history;
+
+import java.io.*;
+import java.nio.file.*;
+import java.time.Instant;
+import java.util.*;
+
+import jdk.internal.org.jline.reader.History;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.utils.Log;
+
+import static jdk.internal.org.jline.reader.LineReader.HISTORY_IGNORE;
+import static jdk.internal.org.jline.reader.impl.ReaderUtils.*;
+
+/**
+ * {@link History} using a file for persistent backing.
+ * <p>
+ * Implementers should install shutdown hook to call {@link DefaultHistory#save}
+ * to save history to disk.
+ * </p>
+ */
+public class DefaultHistory implements History {
+
+    public static final int DEFAULT_HISTORY_SIZE = 500;
+    public static final int DEFAULT_HISTORY_FILE_SIZE = 10000;
+
+    private final LinkedList<Entry> items = new LinkedList<>();
+
+    private LineReader reader;
+
+    private int lastLoaded = 0;
+    private int nbEntriesInFile = 0;
+    private int offset = 0;
+    private int index = 0;
+
+    public DefaultHistory() {
+    }
+
+    public DefaultHistory(LineReader reader) {
+        attach(reader);
+    }
+
+    private Path getPath() {
+        Object obj = reader != null ? reader.getVariables().get(LineReader.HISTORY_FILE) : null;
+        if (obj instanceof Path) {
+            return (Path) obj;
+        } else if (obj instanceof File) {
+            return ((File) obj).toPath();
+        } else if (obj != null) {
+            return Paths.get(obj.toString());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void attach(LineReader reader) {
+        if (this.reader != reader) {
+            this.reader = reader;
+            try {
+                load();
+            }
+            catch (IOException e) {
+                Log.warn("Failed to load history", e);
+            }
+        }
+    }
+
+    @Override
+    public void load() throws IOException {
+        Path path = getPath();
+        if (path != null) {
+            try {
+                if (Files.exists(path)) {
+                    Log.trace("Loading history from: ", path);
+                    try (BufferedReader reader = Files.newBufferedReader(path)) {
+                        internalClear();
+                        reader.lines().forEach(line -> addHistoryLine(path, line));
+                        lastLoaded = items.size();
+                        nbEntriesInFile = lastLoaded;
+                        maybeResize();
+                    }
+                }
+            } catch (IOException e) {
+                Log.debug("Failed to load history; clearing", e);
+                internalClear();
+                throw e;
+            }
+        }
+    }
+
+    protected void addHistoryLine(Path path, String line) {
+        if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
+            int idx = line.indexOf(':');
+            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.");
+            }
+            Instant time = Instant.ofEpochMilli(Long.parseLong(line.substring(0, idx)));
+            String unescaped = unescape(line.substring(idx + 1));
+            internalAdd(time, unescaped);
+        }
+        else {
+            internalAdd(Instant.now(), unescape(line));
+        }
+    }
+
+    @Override
+    public void purge() throws IOException {
+        internalClear();
+        Path path = getPath();
+        if (path != null) {
+            Log.trace("Purging history from: ", path);
+            Files.deleteIfExists(path);
+        }
+    }
+
+    @Override
+    public void save() throws IOException {
+        Path path = getPath();
+        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())) {
+                    if (isPersistable(entry)) {
+                        writer.append(format(entry));
+                    }
+                }
+            }
+            nbEntriesInFile += items.size() - lastLoaded;
+            // If we are over 25% max size, trim history file
+            int max = getInt(reader, LineReader.HISTORY_FILE_SIZE, DEFAULT_HISTORY_FILE_SIZE);
+            if (nbEntriesInFile > max + max / 4) {
+                trimHistory(path, max);
+            }
+        }
+        lastLoaded = items.size();
+    }
+
+    protected void trimHistory(Path path, int max) throws IOException {
+        Log.trace("Trimming history path: ", path);
+        // Load all history entries
+        LinkedList<Entry> allItems = new LinkedList<>();
+        try (BufferedReader reader = Files.newBufferedReader(path)) {
+            reader.lines().forEach(l -> {
+                int idx = l.indexOf(':');
+                Instant time = Instant.ofEpochMilli(Long.parseLong(l.substring(0, idx)));
+                String line = unescape(l.substring(idx + 1));
+                allItems.add(createEntry(allItems.size(), time, line));
+            });
+        }
+        // Remove duplicates
+        doTrimHistory(allItems, max);
+        // Write history
+        Path temp = Files.createTempFile(path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp");
+        try (BufferedWriter writer = Files.newBufferedWriter(temp, StandardOpenOption.WRITE)) {
+            for (Entry entry : allItems) {
+                writer.append(format(entry));
+            }
+        }
+        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();
+        maybeResize();
+    }
+
+    /**
+     * Create a history entry. Subclasses may override to use their own entry implementations.
+     * @param index index of history entry
+     * @param time entry creation time
+     * @param line the entry text
+     * @return entry object
+     */
+    protected EntryImpl createEntry(int index, Instant time, String line) {
+        return new EntryImpl(index, time, line);
+    }
+
+    private void internalClear() {
+        offset = 0;
+        index = 0;
+        lastLoaded = 0;
+        nbEntriesInFile = 0;
+        items.clear();
+    }
+
+    static void doTrimHistory(List<Entry> allItems, int max) {
+        int idx = 0;
+        while (idx < allItems.size()) {
+            int ridx = allItems.size() - idx - 1;
+            String line = allItems.get(ridx).line().trim();
+            ListIterator<Entry> iterator = allItems.listIterator(ridx);
+            while (iterator.hasPrevious()) {
+                String l = iterator.previous().line();
+                if (line.equals(l.trim())) {
+                    iterator.remove();
+                }
+            }
+            idx++;
+        }
+        while (allItems.size() > max) {
+            allItems.remove(0);
+        }
+    }
+
+    public int size() {
+        return items.size();
+    }
+
+    public boolean isEmpty() {
+        return items.isEmpty();
+    }
+
+    public int index() {
+        return offset + index;
+    }
+
+    public int first() {
+        return offset;
+    }
+
+    public int last() {
+        return offset + items.size() - 1;
+    }
+
+    private String format(Entry entry) {
+        if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) {
+            return Long.toString(entry.time().toEpochMilli()) + ":" + escape(entry.line()) + "\n";
+        }
+        return escape(entry.line()) + "\n";
+    }
+
+    public String get(final int index) {
+        return items.get(index - offset).line();
+    }
+
+    @Override
+    public void add(Instant time, String line) {
+        Objects.requireNonNull(time);
+        Objects.requireNonNull(line);
+
+        if (getBoolean(reader, LineReader.DISABLE_HISTORY, false)) {
+            return;
+        }
+        if (isSet(reader, LineReader.Option.HISTORY_IGNORE_SPACE) && line.startsWith(" ")) {
+            return;
+        }
+        if (isSet(reader, LineReader.Option.HISTORY_REDUCE_BLANKS)) {
+            line = line.trim();
+        }
+        if (isSet(reader, LineReader.Option.HISTORY_IGNORE_DUPS)) {
+            if (!items.isEmpty() && line.equals(items.getLast().line())) {
+                return;
+            }
+        }
+        if (matchPatterns(getString(reader, HISTORY_IGNORE, ""), line)) {
+            return;
+        }
+        internalAdd(time, line);
+        if (isSet(reader, LineReader.Option.HISTORY_INCREMENTAL)) {
+            try {
+                save();
+            }
+            catch (IOException e) {
+                Log.warn("Failed to save history", e);
+            }
+        }
+    }
+
+    protected boolean matchPatterns(String patterns, String line) {
+        if (patterns == null || patterns.isEmpty()) {
+            return false;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < patterns.length(); i++) {
+            char ch = patterns.charAt(i);
+            if (ch == '\\') {
+                ch = patterns.charAt(++i);
+                sb.append(ch);
+            } else if (ch == ':') {
+                sb.append('|');
+            } else if (ch == '*') {
+                sb.append('.').append('*');
+            }
+        }
+        return line.matches(sb.toString());
+    }
+
+    protected void internalAdd(Instant time, String line) {
+        Entry entry = new EntryImpl(offset + items.size(), time, line);
+        items.add(entry);
+        maybeResize();
+    }
+
+    private void maybeResize() {
+        while (size() > getInt(reader, LineReader.HISTORY_SIZE, DEFAULT_HISTORY_SIZE)) {
+            items.removeFirst();
+            lastLoaded--;
+            offset++;
+        }
+        index = size();
+    }
+
+    public ListIterator<Entry> iterator(int index) {
+        return items.listIterator(index - offset);
+    }
+
+    @Override
+    public Spliterator<Entry> spliterator() {
+        return items.spliterator();
+    }
+
+    protected static class EntryImpl implements Entry {
+
+        private final int index;
+        private final Instant time;
+        private final String line;
+
+        public EntryImpl(int index, Instant time, String line) {
+            this.index = index;
+            this.time = time;
+            this.line = line;
+        }
+
+        public int index() {
+            return index;
+        }
+
+        public Instant time() {
+            return time;
+        }
+
+        public String line() {
+            return line;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%d: %s", index, line);
+        }
+    }
+
+    //
+    // Navigation
+    //
+
+    /**
+     * This moves the history to the last entry. This entry is one position
+     * before the moveToEnd() position.
+     *
+     * @return Returns false if there were no history iterator or the history
+     * index was already at the last entry.
+     */
+    public boolean moveToLast() {
+        int lastEntry = size() - 1;
+        if (lastEntry >= 0 && lastEntry != index) {
+            index = size() - 1;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Move to the specified index in the history
+     */
+    public boolean moveTo(int index) {
+        index -= offset;
+        if (index >= 0 && index < size()) {
+            this.index = index;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Moves the history index to the first entry.
+     *
+     * @return Return false if there are no iterator in the history or if the
+     * history is already at the beginning.
+     */
+    public boolean moveToFirst() {
+        if (size() > 0 && index != 0) {
+            index = 0;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Move to the end of the history buffer. This will be a blank entry, after
+     * all of the other iterator.
+     */
+    public void moveToEnd() {
+        index = size();
+    }
+
+    /**
+     * Return the content of the current buffer.
+     */
+    public String current() {
+        if (index >= size()) {
+            return "";
+        }
+        return items.get(index).line();
+    }
+
+    /**
+     * Move the pointer to the previous element in the buffer.
+     *
+     * @return true if we successfully went to the previous element
+     */
+    public boolean previous() {
+        if (index <= 0) {
+            return false;
+        }
+        index--;
+        return true;
+    }
+
+    /**
+     * Move the pointer to the next element in the buffer.
+     *
+     * @return true if we successfully went to the next element
+     */
+    public boolean next() {
+        if (index >= size()) {
+            return false;
+        }
+        index++;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (Entry e : this) {
+            sb.append(e.toString()).append("\n");
+        }
+        return sb.toString();
+    }
+
+    private static String escape(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            char ch = s.charAt(i);
+            switch (ch) {
+                case '\n':
+                    sb.append('\\');
+                    sb.append('n');
+                    break;
+                case '\r':
+                    sb.append('\\');
+                    sb.append('r');
+                    break;
+                case '\\':
+                    sb.append('\\');
+                    sb.append('\\');
+                    break;
+                default:
+                    sb.append(ch);
+                    break;
+            }
+        }
+        return sb.toString();
+    }
+
+    static String unescape(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            char ch = s.charAt(i);
+            switch (ch) {
+                case '\\':
+                    ch = s.charAt(++i);
+                    if (ch == 'n') {
+                        sb.append('\n');
+                    } else if (ch == 'r') {
+                        sb.append('\r');
+                    } else {
+                        sb.append(ch);
+                    }
+                    break;
+                default:
+                    sb.append(ch);
+                    break;
+            }
+        }
+        return sb.toString();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/package-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,14 @@
+/*
+ * 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
+ */
+/**
+ * JLine 3.
+ *
+ * @since 3.0
+ */
+package jdk.internal.org.jline.reader.impl.history;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/package-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,14 @@
+/*
+ * 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
+ */
+/**
+ * JLine 3.
+ *
+ * @since 3.0
+ */
+package jdk.internal.org.jline.reader;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Attributes.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,349 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class Attributes {
+
+    /**
+     * Control characters
+     */
+    public enum ControlChar {
+        VEOF,
+        VEOL,
+        VEOL2,
+        VERASE,
+        VWERASE,
+        VKILL,
+        VREPRINT,
+        VINTR,
+        VQUIT,
+        VSUSP,
+        VDSUSP,
+        VSTART,
+        VSTOP,
+        VLNEXT,
+        VDISCARD,
+        VMIN,
+        VTIME,
+        VSTATUS
+    }
+
+    /**
+     * Input flags - software input processing
+     */
+    public enum InputFlag {
+        IGNBRK,       /* ignore BREAK condition */
+        BRKINT,       /* map BREAK to SIGINTR */
+        IGNPAR,       /* ignore (discard) parity errors */
+        PARMRK,       /* mark parity and framing errors */
+        INPCK,        /* enable checking of parity errors */
+        ISTRIP,       /* strip 8th bit off chars */
+        INLCR,        /* map NL into CR */
+        IGNCR,        /* ignore CR */
+        ICRNL,        /* map CR to NL (ala CRMOD) */
+        IXON,         /* enable output flow control */
+        IXOFF,        /* enable input flow control */
+        IXANY,        /* any char will restart after stop */
+        IMAXBEL,      /* ring bell on input queue full */
+        IUTF8         /* maintain state for UTF-8 VERASE */
+    }
+
+    /*
+     * Output flags - software output processing
+     */
+    public enum OutputFlag {
+        OPOST,       /* enable following output processing */
+        ONLCR,       /* map NL to CR-NL (ala CRMOD) */
+        OXTABS,      /* expand tabs to spaces */
+        ONOEOT,      /* discard EOT's (^D) on output) */
+        OCRNL,       /* map CR to NL on output */
+        ONOCR,       /* no CR output at column 0 */
+        ONLRET,      /* NL performs CR function */
+        OFILL,       /* use fill characters for delay */
+        NLDLY,       /* \n delay */
+        TABDLY,      /* horizontal tab delay */
+        CRDLY,       /* \r delay */
+        FFDLY,       /* form feed delay */
+        BSDLY,       /* \b delay */
+        VTDLY,       /* vertical tab delay */
+        OFDEL        /* fill is DEL, else NUL */
+    }
+
+    /*
+     * Control flags - hardware control of terminal
+     */
+    public enum ControlFlag {
+        CIGNORE,          /* ignore control flags */
+        CS5,              /* 5 bits    (pseudo) */
+        CS6,              /* 6 bits */
+        CS7,              /* 7 bits */
+        CS8,              /* 8 bits */
+        CSTOPB,           /* send 2 stop bits */
+        CREAD,            /* enable receiver */
+        PARENB,           /* parity enable */
+        PARODD,           /* odd parity, else even */
+        HUPCL,            /* hang up on last close */
+        CLOCAL,           /* ignore modem status lines */
+        CCTS_OFLOW,       /* CTS flow control of output */
+        CRTS_IFLOW,       /* RTS flow control of input */
+        CDTR_IFLOW,       /* DTR flow control of input */
+        CDSR_OFLOW,       /* DSR flow control of output */
+        CCAR_OFLOW        /* DCD flow control of output */
+    }
+
+    /*
+     * "Local" flags - dumping ground for other state
+     *
+     * Warning: some flags in this structure begin with
+     * the letter "I" and look like they belong in the
+     * input flag.
+     */
+    public enum LocalFlag {
+        ECHOKE,           /* visual erase for line kill */
+        ECHOE,            /* visually erase chars */
+        ECHOK,            /* echo NL after line kill */
+        ECHO,             /* enable echoing */
+        ECHONL,           /* echo NL even if ECHO is off */
+        ECHOPRT,          /* visual erase mode for hardcopy */
+        ECHOCTL,          /* echo control chars as ^(Char) */
+        ISIG,             /* enable signals INTR, QUIT, [D]SUSP */
+        ICANON,           /* canonicalize input lines */
+        ALTWERASE,        /* use alternate WERASE algorithm */
+        IEXTEN,           /* enable DISCARD and LNEXT */
+        EXTPROC,          /* external processing */
+        TOSTOP,           /* stop background jobs from output */
+        FLUSHO,           /* output being flushed (state) */
+        NOKERNINFO,       /* no kernel output from VSTATUS */
+        PENDIN,           /* XXX retype pending input (state) */
+        NOFLSH            /* don't flush after interrupt */
+    }
+
+    final EnumSet<InputFlag> iflag = EnumSet.noneOf(InputFlag.class);
+    final EnumSet<OutputFlag> oflag = EnumSet.noneOf(OutputFlag.class);
+    final EnumSet<ControlFlag> cflag = EnumSet.noneOf(ControlFlag.class);
+    final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class);
+    final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class);
+
+    public Attributes() {
+    }
+
+    public Attributes(Attributes attr) {
+        copy(attr);
+    }
+
+    //
+    // Input flags
+    //
+
+    public EnumSet<InputFlag> getInputFlags() {
+        return iflag;
+    }
+
+    public void setInputFlags(EnumSet<InputFlag> flags) {
+        iflag.clear();
+        iflag.addAll(flags);
+    }
+
+    public boolean getInputFlag(InputFlag flag) {
+        return iflag.contains(flag);
+    }
+
+    public void setInputFlags(EnumSet<InputFlag> flags, boolean value) {
+        if (value) {
+            iflag.addAll(flags);
+        } else {
+            iflag.removeAll(flags);
+        }
+    }
+
+    public void setInputFlag(InputFlag flag, boolean value) {
+        if (value) {
+            iflag.add(flag);
+        } else {
+            iflag.remove(flag);
+        }
+    }
+
+    //
+    // Output flags
+    //
+
+    public EnumSet<OutputFlag> getOutputFlags() {
+        return oflag;
+    }
+
+    public void setOutputFlags(EnumSet<OutputFlag> flags) {
+        oflag.clear();
+        oflag.addAll(flags);
+    }
+
+    public boolean getOutputFlag(OutputFlag flag) {
+        return oflag.contains(flag);
+    }
+
+    public void setOutputFlags(EnumSet<OutputFlag> flags, boolean value) {
+        if (value) {
+            oflag.addAll(flags);
+        } else {
+            oflag.removeAll(flags);
+        }
+    }
+
+    public void setOutputFlag(OutputFlag flag, boolean value) {
+        if (value) {
+            oflag.add(flag);
+        } else {
+            oflag.remove(flag);
+        }
+    }
+
+    //
+    // Control flags
+    //
+
+    public EnumSet<ControlFlag> getControlFlags() {
+        return cflag;
+    }
+
+    public void setControlFlags(EnumSet<ControlFlag> flags) {
+        cflag.clear();
+        cflag.addAll(flags);
+    }
+
+    public boolean getControlFlag(ControlFlag flag) {
+        return cflag.contains(flag);
+    }
+
+    public void setControlFlags(EnumSet<ControlFlag> flags, boolean value) {
+        if (value) {
+            cflag.addAll(flags);
+        } else {
+            cflag.removeAll(flags);
+        }
+    }
+
+    public void setControlFlag(ControlFlag flag, boolean value) {
+        if (value) {
+            cflag.add(flag);
+        } else {
+            cflag.remove(flag);
+        }
+    }
+
+    //
+    // Local flags
+    //
+
+    public EnumSet<LocalFlag> getLocalFlags() {
+        return lflag;
+    }
+
+    public void setLocalFlags(EnumSet<LocalFlag> flags) {
+        lflag.clear();
+        lflag.addAll(flags);
+    }
+
+    public boolean getLocalFlag(LocalFlag flag) {
+        return lflag.contains(flag);
+    }
+
+    public void setLocalFlags(EnumSet<LocalFlag> flags, boolean value) {
+        if (value) {
+            lflag.addAll(flags);
+        } else {
+            lflag.removeAll(flags);
+        }
+    }
+
+    public void setLocalFlag(LocalFlag flag, boolean value) {
+        if (value) {
+            lflag.add(flag);
+        } else {
+            lflag.remove(flag);
+        }
+    }
+
+    //
+    // Control chars
+    //
+
+    public EnumMap<ControlChar, Integer> getControlChars() {
+        return cchars;
+    }
+
+    public void setControlChars(EnumMap<ControlChar, Integer> chars) {
+        cchars.clear();
+        cchars.putAll(chars);
+    }
+
+    public int getControlChar(ControlChar c) {
+        Integer v = cchars.get(c);
+        return v != null ? v : -1;
+    }
+
+    public void setControlChar(ControlChar c, int value) {
+        cchars.put(c, value);
+    }
+
+    //
+    // Miscellaneous methods
+    //
+
+    public void copy(Attributes attributes) {
+        setControlFlags(attributes.getControlFlags());
+        setInputFlags(attributes.getInputFlags());
+        setLocalFlags(attributes.getLocalFlags());
+        setOutputFlags(attributes.getOutputFlags());
+        setControlChars(attributes.getControlChars());
+    }
+
+    @Override
+    public String toString() {
+        return "Attributes[" +
+                "lflags: " + append(lflag) + ", " +
+                "iflags: " + append(iflag) + ", " +
+                "oflags: " + append(oflag) + ", " +
+                "cflags: " + append(cflag) + ", " +
+                "cchars: " + append(EnumSet.allOf(ControlChar.class), this::display) +
+                "]";
+    }
+
+    private String display(ControlChar c) {
+        String value;
+        int ch = getControlChar(c);
+        if (c == ControlChar.VMIN || c == ControlChar.VTIME) {
+            value = Integer.toString(ch);
+        } else if (ch < 0) {
+            value = "<undef>";
+        } else if (ch < 32) {
+            value = "^" + (char) (ch + 'A' - 1);
+        } else if (ch == 127) {
+            value = "^?";
+        } else if (ch >= 128) {
+            value = String.format("\\u%04x", ch);
+        } else {
+            value = String.valueOf((char) ch);
+        }
+        return c.name().toLowerCase().substring(1) + "=" + value;
+    }
+
+    private <T extends Enum<T>> String append(EnumSet<T> set) {
+        return append(set, e -> e.name().toLowerCase());
+    }
+
+    private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) {
+        return set.stream().map(toString).collect(Collectors.joining(" "));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Cursor.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal;
+
+/**
+ * Class holding the cursor position.
+ *
+ * @see Terminal#getCursorPosition(java.util.function.IntConsumer)
+ */
+public class Cursor {
+
+    private final int x;
+    private final int y;
+
+    public Cursor(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX() {
+        return x;
+    }
+
+    public int getY() {
+        return y;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Cursor) {
+            Cursor c = (Cursor) o;
+            return x == c.x && y == c.y;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return x * 31 + y;
+    }
+
+    @Override
+    public String toString() {
+        return "Cursor[" + "x=" + x + ", y=" + y + ']';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/MouseEvent.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,82 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal;
+
+import java.util.EnumSet;
+
+public class MouseEvent {
+
+    public enum Type {
+        Released,
+        Pressed,
+        Wheel,
+        Moved,
+        Dragged
+    }
+
+    public enum Button {
+        NoButton,
+        Button1,
+        Button2,
+        Button3,
+        WheelUp,
+        WheelDown
+    }
+
+    public enum Modifier {
+        Shift,
+        Alt,
+        Control
+    }
+
+    private final Type type;
+    private final Button button;
+    private final EnumSet<Modifier> modifiers;
+    private final int x;
+    private final int y;
+
+    public MouseEvent(Type type, Button button, EnumSet<Modifier> modifiers, int x, int y) {
+        this.type = type;
+        this.button = button;
+        this.modifiers = modifiers;
+        this.x = x;
+        this.y = y;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    public Button getButton() {
+        return button;
+    }
+
+    public EnumSet<Modifier> getModifiers() {
+        return modifiers;
+    }
+
+    public int getX() {
+        return x;
+    }
+
+    public int getY() {
+        return y;
+    }
+
+    @Override
+    public String toString() {
+        return "MouseEvent[" +
+                "type=" + type +
+                ", button=" + button +
+                ", modifiers=" + modifiers +
+                ", x=" + x +
+                ", y=" + y +
+                ']';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Size.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal;
+
+public class Size {
+
+    private int rows;
+    private int cols;
+
+    public Size() {
+    }
+
+    public Size(int columns, int rows) {
+        this();
+        setColumns(columns);
+        setRows(rows);
+    }
+
+    public int getColumns() {
+        return cols;
+    }
+
+    public void setColumns(int columns) {
+        cols = (short) columns;
+    }
+
+    public int getRows() {
+        return rows;
+    }
+
+    public void setRows(int rows) {
+        this.rows = (short) rows;
+    }
+
+    /**
+     * A cursor position combines a row number with a column position.
+     * <p>
+     * Note each row has {@code col+1} different column positions,
+     * including the right margin.
+     * </p>
+     *
+     * @param col the new column
+     * @param row the new row
+     * @return the cursor position
+     */
+    public int cursorPos(int row, int col) {
+        return row * (cols+1) + col;
+    }
+
+    public void copy(Size size) {
+        setColumns(size.getColumns());
+        setRows(size.getRows());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Size) {
+            Size size = (Size) o;
+            return rows == size.rows && cols == size.cols;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return rows * 31 + cols;
+    }
+
+    @Override
+    public String toString() {
+        return "Size[" + "cols=" + cols + ", rows=" + rows + ']';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import jdk.internal.org.jline.terminal.impl.NativeSignalHandler;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+
+/**
+ * A terminal representing a virtual terminal on the computer.
+ *
+ * Terminals should be closed by calling the {@link #close()} method
+ * in order to restore their original state.
+ */
+public interface Terminal extends Closeable, Flushable {
+
+    /**
+     * Type used for dumb terminals.
+     */
+    String TYPE_DUMB = "dumb";
+    String TYPE_DUMB_COLOR = "dumb-color";
+
+    String getName();
+
+    //
+    // Signal support
+    //
+
+    enum Signal {
+        INT,
+        QUIT,
+        TSTP,
+        CONT,
+        INFO,
+        WINCH
+    }
+
+    interface SignalHandler {
+
+        SignalHandler SIG_DFL = NativeSignalHandler.SIG_DFL;
+        SignalHandler SIG_IGN = NativeSignalHandler.SIG_IGN;
+
+        void handle(Signal signal);
+    }
+
+    SignalHandler handle(Signal signal, SignalHandler handler);
+
+    void raise(Signal signal);
+
+    //
+    // Input / output
+    //
+
+    /**
+     * Retrieve the <code>Reader</code> for this terminal.
+     * This is the standard way to read input from this terminal.
+     * The reader is non blocking.
+     *
+     * @return The non blocking reader
+     */
+    NonBlockingReader reader();
+
+    /**
+     * Retrieve the <code>Writer</code> for this terminal.
+     * This is the standard way to write to this terminal.
+     *
+     * @return The writer
+     */
+    PrintWriter writer();
+
+    /**
+     * Returns the {@link Charset} that should be used to encode characters
+     * for {@link #input()} and {@link #output()}.
+     *
+     * @return The terminal encoding
+     */
+    Charset encoding();
+
+    /**
+     * Retrieve the input stream for this terminal.
+     * In some rare cases, there may be a need to access the
+     * terminal input stream directly. In the usual cases,
+     * use the {@link #reader()} instead.
+     *
+     * @return The input stream
+     *
+     * @see #reader()
+     */
+    InputStream input();
+
+    /**
+     * Retrieve the output stream for this terminal.
+     * In some rare cases, there may be a need to access the
+     * terminal output stream directly. In the usual cases,
+     * use the {@link #writer()} instead.
+     *
+     * @return The output stream
+     *
+     * @see #writer();
+     */
+    OutputStream output();
+
+    //
+    // Input control
+    //
+
+    /**
+     * Whether this terminal supports {@link #pause()} and {@link #resume()} calls.
+     *
+     * @return whether this terminal supports {@link #pause()} and {@link #resume()} calls.
+     * @see #paused()
+     * @see #pause()
+     * @see #resume()
+     */
+    boolean canPauseResume();
+
+    /**
+     * Stop reading the input stream.
+     *
+     * @see #resume()
+     * @see #paused()
+     */
+    void pause();
+
+    /**
+     * Stop reading the input stream and optionally wait for the underlying threads to finish.
+     *
+     * @param wait <code>true</code> to wait until the terminal is actually paused
+     * @throws InterruptedException if the call has been interrupted
+     */
+    void pause(boolean wait) throws InterruptedException;
+
+    /**
+     * Resume reading the input stream.
+     *
+     * @see #pause()
+     * @see #paused()
+     */
+    void resume();
+
+    /**
+     * Check whether the terminal is currently reading the input stream or not.
+     * In order to process signal as quickly as possible, the terminal need to read
+     * the input stream and buffer it internally so that it can detect specific
+     * characters in the input stream (Ctrl+C, Ctrl+D, etc...) and raise the
+     * appropriate signals.
+     * However, there are some cases where this processing should be disabled, for
+     * example when handing the terminal control to a subprocess.
+     *
+     * @return whether the terminal is currently reading the input stream or not
+     *
+     * @see #pause()
+     * @see #resume()
+     */
+    boolean paused();
+
+    //
+    // Pty settings
+    //
+
+    Attributes enterRawMode();
+
+    boolean echo();
+
+    boolean echo(boolean echo);
+
+    Attributes getAttributes();
+
+    void setAttributes(Attributes attr);
+
+    Size getSize();
+
+    void setSize(Size size);
+
+    default int getWidth() {
+        return getSize().getColumns();
+    }
+
+    default int getHeight() {
+        return getSize().getRows();
+    }
+
+    void flush();
+
+    //
+    // Infocmp capabilities
+    //
+
+    String getType();
+
+    boolean puts(Capability capability, Object... params);
+
+    boolean getBooleanCapability(Capability capability);
+
+    Integer getNumericCapability(Capability capability);
+
+    String getStringCapability(Capability capability);
+
+    //
+    // Cursor support
+    //
+
+    /**
+     * Query the terminal to report the cursor position.
+     *
+     * As the response is read from the input stream, some
+     * characters may be read before the cursor position is actually
+     * read. Those characters can be given back using
+     * <code>org.jline.keymap.BindingReader#runMacro(String)</code>
+     *
+     * @param discarded a consumer receiving discarded characters
+     * @return <code>null</code> if cursor position reporting
+     *                  is not supported or a valid cursor position
+     */
+    Cursor getCursorPosition(IntConsumer discarded);
+
+    //
+    // Mouse support
+    //
+
+    enum MouseTracking {
+        /**
+         * Disable mouse tracking
+         */
+        Off,
+        /**
+         * Track button press and release.
+         */
+        Normal,
+        /**
+         * Also report button-motion events.  Mouse movements are reported if the mouse pointer
+         * has moved to a different character cell.
+         */
+        Button,
+        /**
+         * Report all motions events, even if no mouse button is down.
+         */
+        Any
+    }
+
+    /**
+     * Returns <code>true</code> if the terminal has support for mouse.
+     * @return whether mouse is supported by the terminal
+     * @see #trackMouse(MouseTracking)
+     */
+    boolean hasMouseSupport();
+
+    /**
+     * Change the mouse tracking mouse.
+     * To start mouse tracking, this method must be called with a valid mouse tracking mode.
+     * Mouse events will be reported by writing the {@link Capability#key_mouse} to the input stream.
+     * When this character sequence is detected, the {@link #readMouseEvent()} method can be
+     * called to actually read the corresponding mouse event.
+     *
+     * @param tracking the mouse tracking mode
+     * @return <code>true</code> if mouse tracking is supported
+     */
+    boolean trackMouse(MouseTracking tracking);
+
+    /**
+     * Read a MouseEvent from the terminal input stream.
+     * Such an event must have been detected by scanning the terminal's {@link Capability#key_mouse}
+     * in the stream immediately before reading the event.
+     *
+     * @return the decoded mouse event.
+     * @see #trackMouse(MouseTracking)
+     */
+    MouseEvent readMouseEvent();
+
+    /**
+     * Read a MouseEvent from the given input stream.
+     *
+     * @param reader the input supplier
+     * @return the decoded mouse event
+     */
+    MouseEvent readMouseEvent(IntSupplier reader);
+
+    /**
+     * Returns <code>true</code> if the terminal has support for focus tracking.
+     * @return whether focus tracking is supported by the terminal
+     * @see #trackFocus(boolean)
+     */
+    boolean hasFocusSupport();
+
+    /**
+     * Enable or disable focus tracking mode.
+     * When focus tracking has been activated, each time the terminal grabs the focus,
+     * the string "\33[I" will be sent to the input stream and each time the focus is lost,
+     * the string "\33[O" will be sent to the input stream.
+     *
+     * @param tracking whether the focus tracking mode should be enabled or not
+     * @return <code>true</code> if focus tracking is supported
+     */
+    boolean trackFocus(boolean tracking);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,474 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.function.Function;
+
+import jdk.internal.org.jline.terminal.impl.AbstractPosixTerminal;
+import jdk.internal.org.jline.terminal.impl.DumbTerminal;
+import jdk.internal.org.jline.terminal.impl.ExecPty;
+import jdk.internal.org.jline.terminal.impl.ExternalTerminal;
+import jdk.internal.org.jline.terminal.impl.PosixPtyTerminal;
+import jdk.internal.org.jline.terminal.impl.PosixSysTerminal;
+import jdk.internal.org.jline.terminal.spi.JansiSupport;
+import jdk.internal.org.jline.terminal.spi.JnaSupport;
+import jdk.internal.org.jline.terminal.spi.Pty;
+import jdk.internal.org.jline.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.
+ */
+public final class TerminalBuilder {
+
+    //
+    // System properties
+    //
+
+    public static final String PROP_ENCODING = "org.jline.terminal.encoding";
+    public static final String PROP_CODEPAGE = "org.jline.terminal.codepage";
+    public static final String PROP_TYPE = "org.jline.terminal.type";
+    public static final String PROP_JNA = "org.jline.terminal.jna";
+    public static final String PROP_JANSI = "org.jline.terminal.jansi";
+    public static final String PROP_EXEC = "org.jline.terminal.exec";
+    public static final String PROP_DUMB = "org.jline.terminal.dumb";
+    public static final String PROP_DUMB_COLOR = "org.jline.terminal.dumb.color";
+
+    //
+    // Other system properties controlling various jline parts
+    //
+
+    public static final String PROP_NON_BLOCKING_READS = "org.jline.terminal.pty.nonBlockingReads";
+    public static final String PROP_COLOR_DISTANCE = "org.jline.utils.colorDistance";
+    public static final String PROP_DISABLE_ALTERNATE_CHARSET = "org.jline.utils.disableAlternateCharset";
+
+    /**
+     * Returns the default system terminal.
+     * Terminals should be closed properly using the {@link Terminal#close()}
+     * method in order to restore the original terminal state.
+     *
+     * <p>
+     * This call is equivalent to:
+     * <code>builder().build()</code>
+     * </p>
+     *
+     * @return the default system terminal
+     * @throws IOException if an error occurs
+     */
+    public static Terminal terminal() throws IOException {
+        return builder().build();
+    }
+
+    /**
+     * Creates a new terminal builder instance.
+     *
+     * @return a builder
+     */
+    public static TerminalBuilder builder() {
+        return new TerminalBuilder();
+    }
+
+    private String name;
+    private InputStream in;
+    private OutputStream out;
+    private String type;
+    private Charset encoding;
+    private int codepage;
+    private Boolean system;
+    private Boolean jna;
+    private Boolean jansi;
+    private Boolean exec;
+    private Boolean dumb;
+    private Attributes attributes;
+    private Size size;
+    private boolean nativeSignals = false;
+    private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL;
+    private boolean paused = false;
+    private Function<InputStream, InputStream> inputStreamWrapper = in -> in;
+
+    private TerminalBuilder() {
+    }
+
+    public TerminalBuilder name(String name) {
+        this.name = name;
+        return this;
+    }
+
+    public TerminalBuilder streams(InputStream in, OutputStream out) {
+        this.in = in;
+        this.out = out;
+        return this;
+    }
+
+    public TerminalBuilder system(boolean system) {
+        this.system = system;
+        return this;
+    }
+
+    public TerminalBuilder jna(boolean jna) {
+        this.jna = jna;
+        return this;
+    }
+
+    public TerminalBuilder jansi(boolean jansi) {
+        this.jansi = jansi;
+        return this;
+    }
+
+    public TerminalBuilder exec(boolean exec) {
+        this.exec = exec;
+        return this;
+    }
+
+    public TerminalBuilder dumb(boolean dumb) {
+        this.dumb = dumb;
+        return this;
+    }
+
+    public TerminalBuilder type(String type) {
+        this.type = type;
+        return this;
+    }
+
+    /**
+     * Set the encoding to use for reading/writing from the console.
+     * If {@code null} (the default value), JLine will automatically select
+     * a {@link Charset}, usually the default system encoding. However,
+     * on some platforms (e.g. Windows) it may use a different one depending
+     * on the {@link Terminal} implementation.
+     *
+     * <p>Use {@link Terminal#encoding()} to get the {@link Charset} that
+     * should be used for a {@link Terminal}.</p>
+     *
+     * @param encoding The encoding to use or null to automatically select one
+     * @return The builder
+     * @throws UnsupportedCharsetException If the given encoding is not supported
+     * @see Terminal#encoding()
+     */
+    public TerminalBuilder encoding(String encoding) throws UnsupportedCharsetException {
+        return encoding(encoding != null ? Charset.forName(encoding) : null);
+    }
+
+    /**
+     * Set the {@link Charset} to use for reading/writing from the console.
+     * If {@code null} (the default value), JLine will automatically select
+     * a {@link Charset}, usually the default system encoding. However,
+     * on some platforms (e.g. Windows) it may use a different one depending
+     * on the {@link Terminal} implementation.
+     *
+     * <p>Use {@link Terminal#encoding()} to get the {@link Charset} that
+     * should be used to read/write from a {@link Terminal}.</p>
+     *
+     * @param encoding The encoding to use or null to automatically select one
+     * @return The builder
+     * @see Terminal#encoding()
+     */
+    public TerminalBuilder encoding(Charset encoding) {
+        this.encoding = encoding;
+        return this;
+    }
+
+    /**
+     * @param codepage the codepage
+     * @return The builder
+     * @deprecated JLine now writes Unicode output independently from the selected
+     *   code page. Using this option will only make it emulate the selected code
+     *   page for {@link Terminal#input()} and {@link Terminal#output()}.
+     */
+    @Deprecated
+    public TerminalBuilder codepage(int codepage) {
+        this.codepage = codepage;
+        return this;
+    }
+
+    /**
+     * Attributes to use when creating a non system terminal,
+     * i.e. when the builder has been given the input and
+     * outut streams using the {@link #streams(InputStream, OutputStream)} method
+     * or when {@link #system(boolean)} has been explicitely called with
+     * <code>false</code>.
+     *
+     * @param attributes the attributes to use
+     * @return The builder
+     * @see #size(Size)
+     * @see #system(boolean)
+     */
+    public TerminalBuilder attributes(Attributes attributes) {
+        this.attributes = attributes;
+        return this;
+    }
+
+    /**
+     * Initial size to use when creating a non system terminal,
+     * i.e. when the builder has been given the input and
+     * outut streams using the {@link #streams(InputStream, OutputStream)} method
+     * or when {@link #system(boolean)} has been explicitely called with
+     * <code>false</code>.
+     *
+     * @param size the initial size
+     * @return The builder
+     * @see #attributes(Attributes)
+     * @see #system(boolean)
+     */
+    public TerminalBuilder size(Size size) {
+        this.size = size;
+        return this;
+    }
+
+    public TerminalBuilder nativeSignals(boolean nativeSignals) {
+        this.nativeSignals = nativeSignals;
+        return this;
+    }
+
+    public TerminalBuilder signalHandler(Terminal.SignalHandler signalHandler) {
+        this.signalHandler = signalHandler;
+        return this;
+    }
+
+    /**
+     * Initial paused state of the terminal (defaults to false).
+     * By default, the terminal is started, but in some cases,
+     * one might want to make sure the input stream is not consumed
+     * before needed, in which case the terminal needs to be created
+     * in a paused state.
+     * @param paused the initial paused state
+     * @return The builder
+     * @see Terminal#pause()
+     */
+    public TerminalBuilder paused(boolean paused) {
+        this.paused = paused;
+        return this;
+    }
+
+    public TerminalBuilder inputStreamWrapper(Function<InputStream, InputStream> wrapper) {
+        this.inputStreamWrapper = wrapper;
+        return this;
+    }
+
+    public Terminal build() throws IOException {
+        Terminal terminal = doBuild();
+        Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName());
+        if (terminal instanceof AbstractPosixTerminal) {
+            Log.debug(() -> "Using pty " + ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName());
+        }
+        return terminal;
+    }
+
+    private Terminal doBuild() throws IOException {
+        String name = this.name;
+        if (name == null) {
+            name = "JLine terminal";
+        }
+        Charset encoding = this.encoding;
+        if (encoding == null) {
+            String charsetName = System.getProperty(PROP_ENCODING);
+            if (charsetName != null && Charset.isSupported(charsetName)) {
+                encoding = Charset.forName(charsetName);
+            }
+        }
+        int codepage = this.codepage;
+        if (codepage <= 0) {
+            String str = System.getProperty(PROP_CODEPAGE);
+            if (str != null) {
+                codepage = Integer.parseInt(str);
+            }
+        }
+        String type = this.type;
+        if (type == null) {
+            type = System.getProperty(PROP_TYPE);
+        }
+        if (type == null) {
+            type = System.getenv("TERM");
+        }
+        Boolean jna = this.jna;
+        if (jna == null) {
+            jna = getBoolean(PROP_JNA, true);
+        }
+        Boolean jansi = this.jansi;
+        if (jansi == null) {
+            jansi = getBoolean(PROP_JANSI, true);
+        }
+        Boolean exec = this.exec;
+        if (exec == null) {
+            exec = getBoolean(PROP_EXEC, true);
+        }
+        Boolean dumb = this.dumb;
+        if (dumb == null) {
+            dumb = getBoolean(PROP_DUMB, null);
+        }
+        if ((system != null && system) || (system == null && in == null && out == null)) {
+            if (attributes != null || size != null) {
+                Log.warn("Attributes and size fields are ignored when creating a system terminal");
+            }
+            IllegalStateException exception = new IllegalStateException("Unable to create a system terminal");
+            if (OSUtils.IS_WINDOWS) {
+                boolean cygwinTerm = "cygwin".equals(System.getenv("TERM"));
+                boolean ansiPassThrough = OSUtils.IS_CONEMU;
+                //
+                // Cygwin support
+                //
+                if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) && exec && !cygwinTerm) {
+                    try {
+                        Pty pty = ExecPty.current();
+                        // Cygwin defaults to XTERM, but actually supports 256 colors,
+                        // so if the value comes from the environment, change it to xterm-256color
+                        if ("xterm".equals(type) && this.type == null && System.getProperty(PROP_TYPE) == null) {
+                            type = "xterm-256color";
+                        }
+                        return new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
+                    } catch (IOException e) {
+                        // Ignore if not a tty
+                        Log.debug("Error creating EXEC based terminal: ", e.getMessage(), e);
+                        exception.addSuppressed(e);
+                    }
+                }
+                if (jna) {
+                    try {
+                        return load(JnaSupport.class).winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, inputStreamWrapper);
+                    } catch (Throwable t) {
+                        Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
+                        exception.addSuppressed(t);
+                    }
+                }
+                if (jansi) {
+                    try {
+                        return load(JansiSupport.class).winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused);
+                    } catch (Throwable t) {
+                        Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
+                        exception.addSuppressed(t);
+                    }
+                }
+            } else {
+                if (jna) {
+                    try {
+                        Pty pty = load(JnaSupport.class).current();
+                        return new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
+                    } catch (Throwable t) {
+                        // ignore
+                        Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
+                        exception.addSuppressed(t);
+                    }
+                }
+                if (jansi) {
+                    try {
+                        Pty pty = load(JansiSupport.class).current();
+                        return new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
+                    } catch (Throwable t) {
+                        Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
+                        exception.addSuppressed(t);
+                    }
+                }
+                if (exec) {
+                    try {
+                        Pty pty = ExecPty.current();
+                        return new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler);
+                    } catch (Throwable t) {
+                        // Ignore if not a tty
+                        Log.debug("Error creating EXEC based terminal: ", t.getMessage(), t);
+                        exception.addSuppressed(t);
+                    }
+                }
+            }
+            if (dumb == null || dumb) {
+                // forced colored dumb terminal
+                boolean color = getBoolean(PROP_DUMB_COLOR, false);
+                // detect emacs using the env variable
+                if (!color) {
+                    color = System.getenv("INSIDE_EMACS") != null;
+                }
+                // detect Intellij Idea
+                if (!color) {
+                    String command = getParentProcessCommand();
+                    color = command != null && command.contains("idea");
+                }
+                if (!color && dumb == null) {
+                    if (Log.isDebugEnabled()) {
+                        Log.warn("Creating a dumb terminal", exception);
+                    } else {
+                        Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)");
+                    }
+                }
+                return new DumbTerminal(name, color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB,
+                        new FileInputStream(FileDescriptor.in),
+                        new FileOutputStream(FileDescriptor.out),
+                        encoding, signalHandler);
+            } else {
+                throw exception;
+            }
+        } else {
+            if (jna) {
+                try {
+                    Pty pty = load(JnaSupport.class).open(attributes, size);
+                    return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
+                } catch (Throwable t) {
+                    Log.debug("Error creating JNA based terminal: ", t.getMessage(), t);
+                }
+            }
+            if (jansi) {
+                try {
+                    Pty pty = load(JansiSupport.class).open(attributes, size);
+                    return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
+                } catch (Throwable t) {
+                    Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t);
+                }
+            }
+            Terminal terminal = new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused);
+            if (attributes != null) {
+                terminal.setAttributes(attributes);
+            }
+            if (size != null) {
+                terminal.setSize(size);
+            }
+            return terminal;
+        }
+    }
+
+    private static String getParentProcessCommand() {
+        try {
+            Class<?> phClass = Class.forName("java.lang.ProcessHandle");
+            Object current = phClass.getMethod("current").invoke(null);
+            Object parent = ((Optional<?>) phClass.getMethod("parent").invoke(current)).orElse(null);
+            Method infoMethod = phClass.getMethod("info");
+            Object info = infoMethod.invoke(parent);
+            Object command = ((Optional<?>) infoMethod.getReturnType().getMethod("command").invoke(info)).orElse(null);
+            return (String) command;
+        } catch (Throwable t) {
+            return null;
+        }
+    }
+
+    private static Boolean getBoolean(String name, Boolean def) {
+        try {
+            String str = System.getProperty(name);
+            if (str != null) {
+                return Boolean.parseBoolean(str);
+            }
+        } catch (IllegalArgumentException | NullPointerException e) {
+        }
+        return def;
+    }
+
+    private <S> S load(Class<S> clazz) {
+        return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPosixTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,85 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Objects;
+import java.util.function.IntConsumer;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Cursor;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.spi.Pty;
+
+public abstract class AbstractPosixTerminal extends AbstractTerminal {
+
+    protected final Pty pty;
+    protected final Attributes originalAttributes;
+
+    public AbstractPosixTerminal(String name, String type, Pty pty) throws IOException {
+        this(name, type, pty, null, SignalHandler.SIG_DFL);
+    }
+
+    public AbstractPosixTerminal(String name, String type, Pty pty, Charset encoding, SignalHandler signalHandler) throws IOException {
+        super(name, type, encoding, signalHandler);
+        Objects.requireNonNull(pty);
+        this.pty = pty;
+        this.originalAttributes = this.pty.getAttr();
+    }
+
+    public Pty getPty() {
+        return pty;
+    }
+
+    public Attributes getAttributes() {
+        try {
+            return pty.getAttr();
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public void setAttributes(Attributes attr) {
+        try {
+            pty.setAttr(attr);
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public Size getSize() {
+        try {
+            return pty.getSize();
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public void setSize(Size size) {
+        try {
+            pty.setSize(size);
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public void close() throws IOException {
+        super.close();
+        pty.setAttr(originalAttributes);
+        pty.close();
+    }
+
+    @Override
+    public Cursor getCursorPosition(IntConsumer discarded) {
+        return CursorSupport.getCursorPosition(this, discarded);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractPty.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,97 @@
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.spi.Pty;
+import jdk.internal.org.jline.utils.NonBlockingInputStream;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_NON_BLOCKING_READS;
+
+public abstract class AbstractPty implements Pty {
+
+    private Attributes current;
+
+    @Override
+    public void setAttr(Attributes attr) throws IOException {
+        current = new Attributes(attr);
+        doSetAttr(attr);
+    }
+
+    @Override
+    public InputStream getSlaveInput() throws IOException {
+        InputStream si = doGetSlaveInput();
+        if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) {
+            return new PtyInputStream(si);
+        } else {
+            return si;
+        }
+    }
+
+    protected abstract void doSetAttr(Attributes attr) throws IOException;
+
+    protected abstract InputStream doGetSlaveInput() throws IOException;
+
+    protected void checkInterrupted() throws InterruptedIOException {
+        if (Thread.interrupted()) {
+            throw new InterruptedIOException();
+        }
+    }
+
+    class PtyInputStream extends NonBlockingInputStream {
+        final InputStream in;
+        int c = 0;
+
+        PtyInputStream(InputStream in) {
+            this.in = in;
+        }
+
+        @Override
+        public int read(long timeout, boolean isPeek) throws IOException {
+            checkInterrupted();
+            if (c != 0) {
+                int r = c;
+                if (!isPeek) {
+                    c = 0;
+                }
+                return r;
+            } else {
+                setNonBlocking();
+                long start = System.currentTimeMillis();
+                while (true) {
+                    int r = in.read();
+                    if (r >= 0) {
+                        if (isPeek) {
+                            c = r;
+                        }
+                        return r;
+                    }
+                    checkInterrupted();
+                    long cur = System.currentTimeMillis();
+                    if (timeout > 0 && cur - start > timeout) {
+                        return NonBlockingInputStream.READ_EXPIRED;
+                    }
+                }
+            }
+        }
+
+        private void setNonBlocking() {
+            if (current == null
+                    || current.getControlChar(Attributes.ControlChar.VMIN) != 0
+                    || current.getControlChar(Attributes.ControlChar.VTIME) != 1) {
+                try {
+                    Attributes attr = getAttr();
+                    attr.setControlChar(Attributes.ControlChar.VMIN, 0);
+                    attr.setControlChar(Attributes.ControlChar.VTIME, 1);
+                    setAttr(attr);
+                } catch (IOException e) {
+                    throw new IOError(e);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.charset.Charset;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Attributes.ControlChar;
+import jdk.internal.org.jline.terminal.Attributes.InputFlag;
+import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
+import jdk.internal.org.jline.terminal.Cursor;
+import jdk.internal.org.jline.terminal.MouseEvent;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.Curses;
+import jdk.internal.org.jline.utils.InfoCmp;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+import jdk.internal.org.jline.utils.Log;
+import jdk.internal.org.jline.utils.Status;
+
+public abstract class AbstractTerminal implements Terminal {
+
+    protected final String name;
+    protected final String type;
+    protected final Charset encoding;
+    protected final Map<Signal, SignalHandler> handlers = new HashMap<>();
+    protected final Set<Capability> bools = new HashSet<>();
+    protected final Map<Capability, Integer> ints = new HashMap<>();
+    protected final Map<Capability, String> strings = new HashMap<>();
+    protected Status status;
+
+    public AbstractTerminal(String name, String type) throws IOException {
+        this(name, type, null, SignalHandler.SIG_DFL);
+    }
+
+    public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler) throws IOException {
+        this.name = name;
+        this.type = type;
+        this.encoding = encoding != null ? encoding : Charset.defaultCharset();
+        for (Signal signal : Signal.values()) {
+            handlers.put(signal, signalHandler);
+        }
+    }
+
+    public Status getStatus() {
+        return getStatus(true);
+    }
+
+    public Status getStatus(boolean create) {
+        if (status == null && create) {
+            status = new Status(this);
+        }
+        return status;
+    }
+
+    public SignalHandler handle(Signal signal, SignalHandler handler) {
+        Objects.requireNonNull(signal);
+        Objects.requireNonNull(handler);
+        return handlers.put(signal, handler);
+    }
+
+    public void raise(Signal signal) {
+        Objects.requireNonNull(signal);
+        SignalHandler handler = handlers.get(signal);
+        if (handler != SignalHandler.SIG_DFL && handler != SignalHandler.SIG_IGN) {
+            handler.handle(signal);
+        }
+        if (status != null && signal == Signal.WINCH) {
+            status.resize();
+        }
+    }
+
+    public void close() throws IOException {
+        if (status != null) {
+            status.update(null);
+            flush();
+        }
+    }
+
+    protected void echoSignal(Signal signal) {
+        ControlChar cc = null;
+        switch (signal) {
+            case INT:
+                cc = ControlChar.VINTR;
+                break;
+            case QUIT:
+                cc = ControlChar.VQUIT;
+                break;
+            case TSTP:
+                cc = ControlChar.VSUSP;
+                break;
+        }
+        if (cc != null) {
+            int vcc = getAttributes().getControlChar(cc);
+            if (vcc > 0 && vcc < 32) {
+                writer().write(new char[]{'^', (char) (vcc + '@')}, 0, 2);
+            }
+        }
+    }
+
+    public Attributes enterRawMode() {
+        Attributes prvAttr = getAttributes();
+        Attributes newAttr = new Attributes(prvAttr);
+        newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.ECHO, LocalFlag.IEXTEN), false);
+        newAttr.setInputFlags(EnumSet.of(InputFlag.IXON, InputFlag.ICRNL, InputFlag.INLCR), false);
+        newAttr.setControlChar(ControlChar.VMIN, 0);
+        newAttr.setControlChar(ControlChar.VTIME, 1);
+        setAttributes(newAttr);
+        return prvAttr;
+    }
+
+    public boolean echo() {
+        return getAttributes().getLocalFlag(LocalFlag.ECHO);
+    }
+
+    public boolean echo(boolean echo) {
+        Attributes attr = getAttributes();
+        boolean prev = attr.getLocalFlag(LocalFlag.ECHO);
+        if (prev != echo) {
+            attr.setLocalFlag(LocalFlag.ECHO, echo);
+            setAttributes(attr);
+        }
+        return prev;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getKind() {
+        return getClass().getSimpleName();
+    }
+
+    @Override
+    public Charset encoding() {
+        return this.encoding;
+    }
+
+    public void flush() {
+        writer().flush();
+    }
+
+    public boolean puts(Capability capability, Object... params) {
+        String str = getStringCapability(capability);
+        if (str == null) {
+            return false;
+        }
+        Curses.tputs(writer(), str, params);
+        return true;
+    }
+
+    public boolean getBooleanCapability(Capability capability) {
+        return bools.contains(capability);
+    }
+
+    public Integer getNumericCapability(Capability capability) {
+        return ints.get(capability);
+    }
+
+    public String getStringCapability(Capability capability) {
+        return strings.get(capability);
+    }
+
+    protected void parseInfoCmp() {
+        String capabilities = null;
+        if (type != null) {
+            try {
+                capabilities = InfoCmp.getInfoCmp(type);
+            } catch (Exception e) {
+                Log.warn("Unable to retrieve infocmp for type " + type, e);
+            }
+        }
+        if (capabilities == null) {
+            capabilities = InfoCmp.getLoadedInfoCmp("ansi");
+        }
+        InfoCmp.parseInfoCmp(capabilities, bools, ints, strings);
+    }
+
+    @Override
+    public Cursor getCursorPosition(IntConsumer discarded) {
+        return null;
+    }
+
+    private MouseEvent lastMouseEvent = new MouseEvent(
+                MouseEvent.Type.Moved, MouseEvent.Button.NoButton,
+                EnumSet.noneOf(MouseEvent.Modifier.class), 0, 0);
+
+    @Override
+    public boolean hasMouseSupport() {
+        return MouseSupport.hasMouseSupport(this);
+    }
+
+    @Override
+    public boolean trackMouse(MouseTracking tracking) {
+        return MouseSupport.trackMouse(this, tracking);
+    }
+
+    @Override
+    public MouseEvent readMouseEvent() {
+        return lastMouseEvent = MouseSupport.readMouse(this, lastMouseEvent);
+    }
+
+    @Override
+    public MouseEvent readMouseEvent(IntSupplier reader) {
+        return lastMouseEvent = MouseSupport.readMouse(reader, lastMouseEvent);
+    }
+
+    @Override
+    public boolean hasFocusSupport() {
+        return type != null && type.startsWith("xterm");
+    }
+
+    @Override
+    public boolean trackFocus(boolean tracking) {
+        if (hasFocusSupport()) {
+            writer().write(tracking ? "\033[?1004h" : "\033[?1004l");
+            writer().flush();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected void checkInterrupted() throws InterruptedIOException {
+        if (Thread.interrupted()) {
+            throw new InterruptedIOException();
+        }
+    }
+
+    @Override
+    public boolean canPauseResume() {
+        return false;
+    }
+
+    @Override
+    public void pause() {
+    }
+
+    @Override
+    public void pause(boolean wait) throws InterruptedException {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    @Override
+    public boolean paused() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsConsoleWriter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public abstract class AbstractWindowsConsoleWriter extends Writer {
+
+    protected abstract void writeConsole(char[] text, int len) throws IOException;
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        char[] text = cbuf;
+        if (off != 0) {
+            text = new char[len];
+            System.arraycopy(cbuf, off, text, 0, len);
+        }
+
+        synchronized (this.lock) {
+            writeConsole(text, len);
+        }
+    }
+
+    @Override
+    public void flush() {
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,538 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.utils.Curses;
+import jdk.internal.org.jline.utils.InfoCmp;
+import jdk.internal.org.jline.utils.Log;
+import jdk.internal.org.jline.utils.NonBlocking;
+import jdk.internal.org.jline.utils.NonBlockingInputStream;
+import jdk.internal.org.jline.utils.NonBlockingPumpReader;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+import jdk.internal.org.jline.utils.ShutdownHooks;
+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;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * The AbstractWindowsTerminal is used as the base class for windows terminal.
+ * Due to windows limitations, mostly the missing support for ansi sequences,
+ * the only way to create a correct terminal is to use the windows api to set
+ * character attributes, move the cursor, erasing, etc...
+ *
+ * UTF-8 support is also lacking in windows and the code page supposed to
+ * emulate UTF-8 is a bit broken. In order to work around this broken
+ * code page, windows api WriteConsoleW is used directly.  This means that
+ * the writer() becomes the primary output, while the output() is bridged
+ * to the writer() using a WriterOutputStream wrapper.
+ */
+public abstract class AbstractWindowsTerminal extends AbstractTerminal {
+
+    public static final String TYPE_WINDOWS = "windows";
+    public static final String TYPE_WINDOWS_256_COLOR = "windows-256color";
+    public static final String TYPE_WINDOWS_VTP = "windows-vtp";
+
+    public static final int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
+
+    private static final int UTF8_CODE_PAGE = 65001;
+
+    protected static final int ENABLE_PROCESSED_INPUT = 0x0001;
+    protected static final int ENABLE_LINE_INPUT      = 0x0002;
+    protected static final int ENABLE_ECHO_INPUT      = 0x0004;
+    protected static final int ENABLE_WINDOW_INPUT    = 0x0008;
+    protected static final int ENABLE_MOUSE_INPUT     = 0x0010;
+    protected static final int ENABLE_INSERT_MODE     = 0x0020;
+    protected static final int ENABLE_QUICK_EDIT_MODE = 0x0040;
+
+    protected final Writer slaveInputPipe;
+    protected final InputStream input;
+    protected final OutputStream output;
+    protected final NonBlockingReader reader;
+    protected final PrintWriter writer;
+    protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
+    protected final ShutdownHooks.Task closer;
+    protected final Attributes attributes = new Attributes();
+    protected final int originalConsoleMode;
+
+    protected final Object lock = new Object();
+    protected boolean paused = true;
+    protected Thread pump;
+
+    protected MouseTracking tracking = MouseTracking.Off;
+    protected boolean focusTracking = false;
+    private volatile boolean closing;
+
+    public AbstractWindowsTerminal(Writer writer, String name, String type, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
+        super(name, type, selectCharset(encoding, codepage), signalHandler);
+        NonBlockingPumpReader reader = NonBlocking.nonBlockingPumpReader();
+        this.slaveInputPipe = reader.getWriter();
+        this.reader = reader;
+        this.input = inputStreamWrapper.apply(NonBlocking.nonBlockingStream(reader, encoding()));
+        this.writer = new PrintWriter(writer);
+        this.output = new WriterOutputStream(writer, encoding());
+        parseInfoCmp();
+        // Attributes
+        originalConsoleMode = getConsoleMode();
+        attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true);
+        attributes.setControlChar(Attributes.ControlChar.VINTR, ctrl('C'));
+        attributes.setControlChar(Attributes.ControlChar.VEOF,  ctrl('D'));
+        attributes.setControlChar(Attributes.ControlChar.VSUSP, ctrl('Z'));
+        // Handle signals
+        if (nativeSignals) {
+            for (final Signal signal : Signal.values()) {
+                if (signalHandler == SignalHandler.SIG_DFL) {
+                    nativeHandlers.put(signal, Signals.registerDefault(signal.name()));
+                } else {
+                    nativeHandlers.put(signal, Signals.register(signal.name(), () -> raise(signal)));
+                }
+            }
+        }
+        closer = this::close;
+        ShutdownHooks.add(closer);
+        // ConEMU extended fonts support
+        if (TYPE_WINDOWS_256_COLOR.equals(getType())
+                && !Boolean.getBoolean("org.jline.terminal.conemu.disable-activate")) {
+            writer.write("\u001b[9999E");
+            writer.flush();
+        }
+    }
+
+    private static Charset selectCharset(Charset encoding, int codepage) {
+        if (encoding != null) {
+            return encoding;
+        }
+
+        if (codepage >= 0) {
+            return getCodepageCharset(codepage);
+        }
+
+        // Use UTF-8 as default
+        return StandardCharsets.UTF_8;
+    }
+
+    private static Charset getCodepageCharset(int codepage) {
+        //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
+        if (codepage == UTF8_CODE_PAGE) {
+            return StandardCharsets.UTF_8;
+        }
+        String charsetMS = "ms" + codepage;
+        if (Charset.isSupported(charsetMS)) {
+            return Charset.forName(charsetMS);
+        }
+        String charsetCP = "cp" + codepage;
+        if (Charset.isSupported(charsetCP)) {
+            return Charset.forName(charsetCP);
+        }
+        return Charset.defaultCharset();
+    }
+
+    @Override
+    public SignalHandler handle(Signal signal, SignalHandler handler) {
+        SignalHandler prev = super.handle(signal, handler);
+        if (prev != handler) {
+            if (handler == SignalHandler.SIG_DFL) {
+                Signals.registerDefault(signal.name());
+            } else {
+                Signals.register(signal.name(), () -> raise(signal));
+            }
+        }
+        return prev;
+    }
+
+    public NonBlockingReader reader() {
+        return reader;
+    }
+
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public InputStream input() {
+        return input;
+    }
+
+    @Override
+    public OutputStream output() {
+        return output;
+    }
+
+    public Attributes getAttributes() {
+        int mode = getConsoleMode();
+        if ((mode & ENABLE_ECHO_INPUT) != 0) {
+            attributes.setLocalFlag(Attributes.LocalFlag.ECHO, true);
+        }
+        if ((mode & ENABLE_LINE_INPUT) != 0) {
+            attributes.setLocalFlag(Attributes.LocalFlag.ICANON, true);
+        }
+        return new Attributes(attributes);
+    }
+
+    public void setAttributes(Attributes attr) {
+        attributes.copy(attr);
+        updateConsoleMode();
+    }
+
+    protected void updateConsoleMode() {
+        int mode = ENABLE_WINDOW_INPUT;
+        if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
+            mode |= ENABLE_ECHO_INPUT;
+        }
+        if (attributes.getLocalFlag(Attributes.LocalFlag.ICANON)) {
+            mode |= ENABLE_LINE_INPUT;
+        }
+        if (tracking != MouseTracking.Off) {
+            mode |= ENABLE_MOUSE_INPUT;
+        }
+        setConsoleMode(mode);
+    }
+
+    protected int ctrl(char key) {
+        return (Character.toUpperCase(key) & 0x1f);
+    }
+
+    public void setSize(Size size) {
+        throw new UnsupportedOperationException("Can not resize windows terminal");
+    }
+
+    public void close() throws IOException {
+        super.close();
+        closing = true;
+        pump.interrupt();
+        ShutdownHooks.remove(closer);
+        for (Map.Entry<Signal, Object> entry : nativeHandlers.entrySet()) {
+            Signals.unregister(entry.getKey().name(), entry.getValue());
+        }
+        reader.close();
+        writer.close();
+        setConsoleMode(originalConsoleMode);
+    }
+
+    static final int SHIFT_FLAG = 0x01;
+    static final int ALT_FLAG =   0x02;
+    static final int CTRL_FLAG =  0x04;
+
+    static final int RIGHT_ALT_PRESSED =   0x0001;
+    static final int LEFT_ALT_PRESSED =    0x0002;
+    static final int RIGHT_CTRL_PRESSED =  0x0004;
+    static final int LEFT_CTRL_PRESSED =   0x0008;
+    static final int SHIFT_PRESSED =       0x0010;
+    static final int NUMLOCK_ON =          0x0020;
+    static final int SCROLLLOCK_ON =       0x0040;
+    static final int CAPSLOCK_ON =         0x0080;
+
+    protected void processKeyEvent(final boolean isKeyDown, final short virtualKeyCode, char ch, final int controlKeyState) throws IOException {
+        final boolean isCtrl = (controlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) > 0;
+        final boolean isAlt = (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) > 0;
+        final boolean isShift = (controlKeyState & SHIFT_PRESSED) > 0;
+        // key down event
+        if (isKeyDown && ch != '\3') {
+            // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+            // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+            if (ch != 0
+                    && (controlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED | SHIFT_PRESSED))
+                        == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) {
+                processInputChar(ch);
+            } else {
+                final String keySeq = getEscapeSequence(virtualKeyCode, (isCtrl ? CTRL_FLAG : 0) + (isAlt ? ALT_FLAG : 0) + (isShift ? SHIFT_FLAG : 0));
+                if (keySeq != null) {
+                    for (char c : keySeq.toCharArray()) {
+                        processInputChar(c);
+                    }
+                    return;
+                }
+                /* uchar value in Windows when CTRL is pressed:
+                 * 1). Ctrl +  <0x41 to 0x5e>      : uchar=<keyCode> - 'A' + 1
+                 * 2). Ctrl + Backspace(0x08)      : uchar=0x7f
+                 * 3). Ctrl + Enter(0x0d)          : uchar=0x0a
+                 * 4). Ctrl + Space(0x20)          : uchar=0x20
+                 * 5). Ctrl + <Other key>          : uchar=0
+                 * 6). Ctrl + Alt + <Any key>      : uchar=0
+                */
+                if (ch > 0) {
+                    if (isAlt) {
+                        processInputChar('\033');
+                    }
+                    if (isCtrl && ch != ' ' && ch != '\n' && ch != 0x7f) {
+                        processInputChar((char) (ch == '?' ? 0x7f : Character.toUpperCase(ch) & 0x1f));
+                    } else if (isCtrl && ch == '\n') {
+                        //simulate Alt-Enter:
+                        processInputChar('\033');
+                        processInputChar('\r');
+                    } else {
+                        processInputChar(ch);
+                    }
+                } else if (isCtrl) { //Handles the ctrl key events(uchar=0)
+                    if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') {
+                        ch = (char) (virtualKeyCode - 0x40);
+                    } else if (virtualKeyCode == 191) { //?
+                        ch = 127;
+                    }
+                    if (ch > 0) {
+                        if (isAlt) {
+                            processInputChar('\033');
+                        }
+                        processInputChar(ch);
+                    }
+                }
+            }
+        } else if (isKeyDown && ch == '\3') {
+            processInputChar('\3');
+        }
+        // key up event
+        else {
+            // support ALT+NumPad input method
+            if (virtualKeyCode == 0x12 /*VK_MENU ALT key*/ && ch > 0) {
+                processInputChar(ch);  // no such combination in Windows
+            }
+        }
+    }
+
+    protected String getEscapeSequence(short keyCode, int keyState) {
+        // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+        // TODO: numpad keys, modifiers
+        String escapeSequence = null;
+        switch (keyCode) {
+            case 0x08: // VK_BACK BackSpace
+                escapeSequence = (keyState & ALT_FLAG) > 0 ? "\\E^H" : getRawSequence(InfoCmp.Capability.key_backspace);
+                break;
+            case 0x09:
+                escapeSequence = (keyState & SHIFT_FLAG) > 0 ? getRawSequence(InfoCmp.Capability.key_btab) : null;
+                break;
+            case 0x21: // VK_PRIOR PageUp
+                escapeSequence = getRawSequence(InfoCmp.Capability.key_ppage);
+                break;
+            case 0x22: // VK_NEXT PageDown
+                escapeSequence = getRawSequence(InfoCmp.Capability.key_npage);
+                break;
+            case 0x23: // VK_END
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dF" : getRawSequence(InfoCmp.Capability.key_end);
+                break;
+            case 0x24: // VK_HOME
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dH" : getRawSequence(InfoCmp.Capability.key_home);
+                break;
+            case 0x25: // VK_LEFT
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dD" : getRawSequence(InfoCmp.Capability.key_left);
+                break;
+            case 0x26: // VK_UP
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dA" : getRawSequence(InfoCmp.Capability.key_up);
+                break;
+            case 0x27: // VK_RIGHT
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dC" : getRawSequence(InfoCmp.Capability.key_right);
+                break;
+            case 0x28: // VK_DOWN
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dB" : getRawSequence(InfoCmp.Capability.key_down);
+                break;
+            case 0x2D: // VK_INSERT
+                escapeSequence = getRawSequence(InfoCmp.Capability.key_ic);
+                break;
+            case 0x2E: // VK_DELETE
+                escapeSequence = getRawSequence(InfoCmp.Capability.key_dc);
+                break;
+            case 0x70: // VK_F1
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dP" : getRawSequence(InfoCmp.Capability.key_f1);
+                break;
+            case 0x71: // VK_F2
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dQ" : getRawSequence(InfoCmp.Capability.key_f2);
+                break;
+            case 0x72: // VK_F3
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dR" : getRawSequence(InfoCmp.Capability.key_f3);
+                break;
+            case 0x73: // VK_F4
+                escapeSequence = keyState > 0 ? "\\E[1;%p1%dS" : getRawSequence(InfoCmp.Capability.key_f4);
+                break;
+            case 0x74: // VK_F5
+                escapeSequence = keyState > 0 ? "\\E[15;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f5);
+                break;
+            case 0x75: // VK_F6
+                escapeSequence = keyState > 0 ? "\\E[17;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f6);
+                break;
+            case 0x76: // VK_F7
+                escapeSequence = keyState > 0 ? "\\E[18;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f7);
+                break;
+            case 0x77: // VK_F8
+                escapeSequence = keyState > 0 ? "\\E[19;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f8);
+                break;
+            case 0x78: // VK_F9
+                escapeSequence = keyState > 0 ? "\\E[20;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f9);
+                break;
+            case 0x79: // VK_F10
+                escapeSequence = keyState > 0 ? "\\E[21;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f10);
+                break;
+            case 0x7A: // VK_F11
+                escapeSequence = keyState > 0 ? "\\E[23;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f11);
+                break;
+            case 0x7B: // VK_F12
+                escapeSequence = keyState > 0 ? "\\E[24;%p1%d~" : getRawSequence(InfoCmp.Capability.key_f12);
+                break;
+            case 0x5D: // VK_CLOSE_BRACKET(Menu key)
+            case 0x5B: // VK_OPEN_BRACKET(Window key)
+            default:
+                return null;
+        }
+        return Curses.tputs(escapeSequence, keyState + 1);
+    }
+
+    protected String getRawSequence(InfoCmp.Capability cap) {
+        return strings.get(cap);
+    }
+
+    @Override
+    public boolean hasFocusSupport() {
+        return true;
+    }
+
+    @Override
+    public boolean trackFocus(boolean tracking) {
+        focusTracking = tracking;
+        return true;
+    }
+
+    @Override
+    public boolean canPauseResume() {
+        return true;
+    }
+
+    @Override
+    public void pause() {
+        synchronized (lock) {
+            paused = true;
+        }
+    }
+
+    @Override
+    public void pause(boolean wait) throws InterruptedException {
+        Thread p;
+        synchronized (lock) {
+            paused = true;
+            p = pump;
+        }
+        if (p != null) {
+            p.interrupt();
+            p.join();
+        }
+    }
+
+    @Override
+    public void resume() {
+        synchronized (lock) {
+            paused = false;
+            if (pump == null) {
+                pump = new Thread(this::pump, "WindowsStreamPump");
+                pump.setDaemon(true);
+                pump.start();
+            }
+        }
+    }
+
+    @Override
+    public boolean paused() {
+        synchronized (lock) {
+            return paused;
+        }
+    }
+
+    protected void pump() {
+        try {
+            while (!closing) {
+                synchronized (lock) {
+                    if (paused) {
+                        pump = null;
+                        break;
+                    }
+                }
+                if (processConsoleInput()) {
+                    slaveInputPipe.flush();
+                }
+            }
+        } catch (IOException e) {
+            if (!closing) {
+                Log.warn("Error in WindowsStreamPump", e);
+                try {
+                    close();
+                } catch (IOException e1) {
+                    Log.warn("Error closing terminal", e);
+                }
+            }
+        } finally {
+            synchronized (lock) {
+                pump = null;
+            }
+        }
+    }
+
+    public void processInputChar(char c) throws IOException {
+        if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) {
+            if (c == attributes.getControlChar(Attributes.ControlChar.VINTR)) {
+                raise(Signal.INT);
+                return;
+            } else if (c == attributes.getControlChar(Attributes.ControlChar.VQUIT)) {
+                raise(Signal.QUIT);
+                return;
+            } else if (c == attributes.getControlChar(Attributes.ControlChar.VSUSP)) {
+                raise(Signal.TSTP);
+                return;
+            } else if (c == attributes.getControlChar(Attributes.ControlChar.VSTATUS)) {
+                raise(Signal.INFO);
+            }
+        }
+        if (c == '\r') {
+            if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
+                return;
+            }
+            if (attributes.getInputFlag(Attributes.InputFlag.ICRNL)) {
+                c = '\n';
+            }
+        } else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) {
+            c = '\r';
+        }
+//        if (attributes.getLocalFlag(Attributes.LocalFlag.ECHO)) {
+//            processOutputByte(c);
+//            masterOutput.flush();
+//        }
+        slaveInputPipe.write(c);
+    }
+
+    @Override
+    public boolean trackMouse(MouseTracking tracking) {
+        this.tracking = tracking;
+        updateConsoleMode();
+        return true;
+    }
+
+    protected abstract int getConsoleOutputCP();
+
+    protected abstract int getConsoleMode();
+
+    protected abstract void setConsoleMode(int mode);
+
+    /**
+     * Read a single input event from the input buffer and process it.
+     *
+     * @return true if new input was generated from the event
+     * @throws IOException if anything wrong happens
+     */
+    protected abstract boolean processConsoleInput() throws IOException;
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/CursorSupport.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.Cursor;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.Curses;
+import jdk.internal.org.jline.utils.InfoCmp;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.util.function.IntConsumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class CursorSupport {
+
+    public static Cursor getCursorPosition(Terminal terminal, IntConsumer discarded) {
+        try {
+            String u6 = terminal.getStringCapability(InfoCmp.Capability.user6);
+            String u7 = terminal.getStringCapability(InfoCmp.Capability.user7);
+            if (u6 == null || u7 == null) {
+                return null;
+            }
+            // Prepare parser
+            boolean inc1 = false;
+            StringBuilder patb = new StringBuilder();
+            int index = 0;
+            while (index < u6.length()) {
+                char ch;
+                switch (ch = u6.charAt(index++)) {
+                    case '\\':
+                        switch (u6.charAt(index++)) {
+                            case 'e':
+                            case 'E':
+                                patb.append("\\x1b");
+                                break;
+                            default:
+                                throw new IllegalArgumentException();
+                        }
+                        break;
+                    case '%':
+                        ch = u6.charAt(index++);
+                        switch (ch) {
+                            case '%':
+                                patb.append('%');
+                                break;
+                            case 'i':
+                                inc1 = true;
+                                break;
+                            case 'd':
+                                patb.append("([0-9]+)");
+                                break;
+                            default:
+                                throw new IllegalArgumentException();
+                        }
+                        break;
+                    default:
+                        switch (ch) {
+                            case '[':
+                                patb.append('\\');
+                                break;
+                        }
+                        patb.append(ch);
+                        break;
+                }
+            }
+            Pattern pattern = Pattern.compile(patb.toString());
+            // Output cursor position request
+            Curses.tputs(terminal.writer(), u7);
+            terminal.flush();
+            StringBuilder sb = new StringBuilder();
+            int start = 0;
+            while (true) {
+                int c = terminal.reader().read();
+                if (c < 0) {
+                    return null;
+                }
+                sb.append((char) c);
+                Matcher matcher = pattern.matcher(sb.substring(start));
+                if (matcher.matches()) {
+                    int y = Integer.parseInt(matcher.group(1));
+                    int x = Integer.parseInt(matcher.group(2));
+                    if (inc1) {
+                        x--;
+                        y--;
+                    }
+                    if (discarded != null) {
+                        for (int i = 0; i < start; i++) {
+                            discarded.accept(sb.charAt(i));
+                        }
+                    }
+                    return new Cursor(x, y);
+                } else if (!matcher.hitEnd()) {
+                    start++;
+                }
+            }
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/DumbTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Attributes.ControlChar;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.utils.NonBlocking;
+import jdk.internal.org.jline.utils.NonBlockingInputStream;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+
+public class DumbTerminal extends AbstractTerminal {
+
+    private final NonBlockingInputStream input;
+    private final OutputStream output;
+    private final NonBlockingReader reader;
+    private final PrintWriter writer;
+    private final Attributes attributes;
+    private final Size size;
+
+    public DumbTerminal(InputStream in, OutputStream out) throws IOException {
+        this(TYPE_DUMB, TYPE_DUMB, in, out, null);
+    }
+
+    public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding) throws IOException {
+        this(name, type, in, out, encoding, SignalHandler.SIG_DFL);
+    }
+
+    public DumbTerminal(String name, String type, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
+        super(name, type, encoding, signalHandler);
+        NonBlockingInputStream nbis = NonBlocking.nonBlocking(getName(), in);
+        this.input = new NonBlockingInputStream() {
+            @Override
+            public int read(long timeout, boolean isPeek) throws IOException {
+                for (;;) {
+                    int c = nbis.read(timeout, isPeek);
+                    if (attributes.getLocalFlag(Attributes.LocalFlag.ISIG)) {
+                        if (c == attributes.getControlChar(ControlChar.VINTR)) {
+                            raise(Signal.INT);
+                            continue;
+                        } else if (c == attributes.getControlChar(ControlChar.VQUIT)) {
+                            raise(Signal.QUIT);
+                            continue;
+                        } else if (c == attributes.getControlChar(ControlChar.VSUSP)) {
+                            raise(Signal.TSTP);
+                            continue;
+                        } else if (c == attributes.getControlChar(ControlChar.VSTATUS)) {
+                            raise(Signal.INFO);
+                            continue;
+                        }
+                    }
+                    if (c == '\r') {
+                        if (attributes.getInputFlag(Attributes.InputFlag.IGNCR)) {
+                            continue;
+                        }
+                        if (attributes.getInputFlag(Attributes.InputFlag.ICRNL)) {
+                            c = '\n';
+                        }
+                    } else if (c == '\n' && attributes.getInputFlag(Attributes.InputFlag.INLCR)) {
+                        c = '\r';
+                    }
+                    return c;
+                }
+            }
+        };
+        this.output = out;
+        this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
+        this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
+        this.attributes = new Attributes();
+        this.attributes.setControlChar(ControlChar.VERASE,  (char) 127);
+        this.attributes.setControlChar(ControlChar.VWERASE, (char) 23);
+        this.attributes.setControlChar(ControlChar.VKILL,   (char) 21);
+        this.attributes.setControlChar(ControlChar.VLNEXT,  (char) 22);
+        this.size = new Size();
+        parseInfoCmp();
+    }
+
+    public NonBlockingReader reader() {
+        return reader;
+    }
+
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public InputStream input() {
+        return input;
+    }
+
+    @Override
+    public OutputStream output() {
+        return output;
+    }
+
+    public Attributes getAttributes() {
+        Attributes attr = new Attributes();
+        attr.copy(attributes);
+        return attr;
+    }
+
+    public void setAttributes(Attributes attr) {
+        attributes.copy(attr);
+    }
+
+    public Size getSize() {
+        Size sz = new Size();
+        sz.copy(size);
+        return sz;
+    }
+
+    public void setSize(Size sz) {
+        size.copy(sz);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExecPty.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,302 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileDescriptor;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Attributes.ControlChar;
+import jdk.internal.org.jline.terminal.Attributes.ControlFlag;
+import jdk.internal.org.jline.terminal.Attributes.InputFlag;
+import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
+import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.spi.Pty;
+import jdk.internal.org.jline.utils.OSUtils;
+
+import static jdk.internal.org.jline.utils.ExecHelper.exec;
+
+public class ExecPty extends AbstractPty implements Pty {
+
+    private final String name;
+    private final boolean system;
+
+    public static Pty current() throws IOException {
+        try {
+            String result = exec(true, OSUtils.TTY_COMMAND);
+            return new ExecPty(result.trim(), true);
+        } catch (IOException e) {
+            throw new IOException("Not a tty", e);
+        }
+    }
+
+    protected ExecPty(String name, boolean system) {
+        this.name = name;
+        this.system = system;
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public InputStream getMasterInput() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public OutputStream getMasterOutput() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected InputStream doGetSlaveInput() throws IOException {
+        return system
+                ? new FileInputStream(FileDescriptor.in)
+                : new FileInputStream(getName());
+    }
+
+    @Override
+    public OutputStream getSlaveOutput() throws IOException {
+        return system
+                ? new FileOutputStream(FileDescriptor.out)
+                : new FileOutputStream(getName());
+    }
+
+    @Override
+    public Attributes getAttr() throws IOException {
+        String cfg = doGetConfig();
+        return doGetAttr(cfg);
+    }
+
+    @Override
+    protected void doSetAttr(Attributes attr) throws IOException {
+        List<String> commands = getFlagsToSet(attr, getAttr());
+        if (!commands.isEmpty()) {
+            commands.add(0, OSUtils.STTY_COMMAND);
+            if (!system) {
+                commands.add(1, OSUtils.STTY_F_OPTION);
+                commands.add(2, getName());
+            }
+            try {
+                exec(system, commands.toArray(new String[commands.size()]));
+            } catch (IOException e) {
+                // Handle partial failures with GNU stty, see #97
+                if (e.toString().contains("unable to perform all requested operations")) {
+                    commands = getFlagsToSet(attr, getAttr());
+                    if (!commands.isEmpty()) {
+                        throw new IOException("Could not set the following flags: " + String.join(", ", commands), e);
+                    }
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    protected List<String> getFlagsToSet(Attributes attr, Attributes current) {
+        List<String> commands = new ArrayList<>();
+        for (InputFlag flag : InputFlag.values()) {
+            if (attr.getInputFlag(flag) != current.getInputFlag(flag)) {
+                commands.add((attr.getInputFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
+            }
+        }
+        for (OutputFlag flag : OutputFlag.values()) {
+            if (attr.getOutputFlag(flag) != current.getOutputFlag(flag)) {
+                commands.add((attr.getOutputFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
+            }
+        }
+        for (ControlFlag flag : ControlFlag.values()) {
+            if (attr.getControlFlag(flag) != current.getControlFlag(flag)) {
+                commands.add((attr.getControlFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
+            }
+        }
+        for (LocalFlag flag : LocalFlag.values()) {
+            if (attr.getLocalFlag(flag) != current.getLocalFlag(flag)) {
+                commands.add((attr.getLocalFlag(flag) ? flag.name() : "-" + flag.name()).toLowerCase());
+            }
+        }
+        String undef = System.getProperty("os.name").toLowerCase().startsWith("hp") ? "^-" : "undef";
+        for (ControlChar cchar : ControlChar.values()) {
+            if (attr.getControlChar(cchar) != current.getControlChar(cchar)) {
+                String str = "";
+                int v = attr.getControlChar(cchar);
+                commands.add(cchar.name().toLowerCase().substring(1));
+                if (cchar == ControlChar.VMIN || cchar == ControlChar.VTIME) {
+                    commands.add(Integer.toBinaryString(v));
+                }
+                else if (v == 0) {
+                    commands.add(undef);
+                }
+                else {
+                    if (v >= 128) {
+                        v -= 128;
+                        str += "M-";
+                    }
+                    if (v < 32 || v == 127) {
+                        v ^= 0x40;
+                        str += "^";
+                    }
+                    str += (char) v;
+                    commands.add(str);
+                }
+            }
+        }
+        return commands;
+    }
+
+    @Override
+    public Size getSize() throws IOException {
+        String cfg = doGetConfig();
+        return doGetSize(cfg);
+    }
+
+    protected String doGetConfig() throws IOException {
+        return system
+                ? exec(true,  OSUtils.STTY_COMMAND, "-a")
+                : exec(false, OSUtils.STTY_COMMAND, OSUtils.STTY_F_OPTION, getName(), "-a");
+    }
+
+    static Attributes doGetAttr(String cfg) throws IOException {
+        Attributes attributes = new Attributes();
+        for (InputFlag flag : InputFlag.values()) {
+            Boolean value = doGetFlag(cfg, flag);
+            if (value != null) {
+                attributes.setInputFlag(flag, value);
+            }
+        }
+        for (OutputFlag flag : OutputFlag.values()) {
+            Boolean value = doGetFlag(cfg, flag);
+            if (value != null) {
+                attributes.setOutputFlag(flag, value);
+            }
+        }
+        for (ControlFlag flag : ControlFlag.values()) {
+            Boolean value = doGetFlag(cfg, flag);
+            if (value != null) {
+                attributes.setControlFlag(flag, value);
+            }
+        }
+        for (LocalFlag flag : LocalFlag.values()) {
+            Boolean value = doGetFlag(cfg, flag);
+            if (value != null) {
+                attributes.setLocalFlag(flag, value);
+            }
+        }
+        for (ControlChar cchar : ControlChar.values()) {
+            String name = cchar.name().toLowerCase().substring(1);
+            if ("reprint".endsWith(name)) {
+                name = "(?:reprint|rprnt)";
+            }
+            Matcher matcher = Pattern.compile("[\\s;]" + name + "\\s*=\\s*(.+?)[\\s;]").matcher(cfg);
+            if (matcher.find()) {
+                attributes.setControlChar(cchar, parseControlChar(matcher.group(1).toUpperCase()));
+            }
+        }
+        return attributes;
+    }
+
+    private static Boolean doGetFlag(String cfg, Enum<?> flag) {
+        Matcher matcher = Pattern.compile("(?:^|[\\s;])(\\-?" + flag.name().toLowerCase() + ")(?:[\\s;]|$)").matcher(cfg);
+        return matcher.find() ? !matcher.group(1).startsWith("-") : null;
+    }
+
+    static int parseControlChar(String str) {
+        // undef
+        if ("<UNDEF>".equals(str)) {
+            return -1;
+        }
+        // del
+        if ("DEL".equalsIgnoreCase(str)) {
+            return 127;
+        }
+        // octal
+        if (str.charAt(0) == '0') {
+            return Integer.parseInt(str, 8);
+        }
+        // decimal
+        if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
+            return Integer.parseInt(str, 10);
+        }
+        // control char
+        if (str.charAt(0) == '^') {
+            if (str.charAt(1) == '?') {
+                return 127;
+            } else {
+                return str.charAt(1) - 64;
+            }
+        } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
+            if (str.charAt(2) == '^') {
+                if (str.charAt(3) == '?') {
+                    return 127 + 128;
+                } else {
+                    return str.charAt(3) - 64 + 128;
+                }
+            } else {
+                return str.charAt(2) + 128;
+            }
+        } else {
+            return str.charAt(0);
+        }
+    }
+
+    static Size doGetSize(String cfg) throws IOException {
+        return new Size(doGetInt("columns", cfg), doGetInt("rows", cfg));
+    }
+
+    static int doGetInt(String name, String cfg) throws IOException {
+        String[] patterns = new String[] {
+                "\\b([0-9]+)\\s+" + name + "\\b",
+                "\\b" + name + "\\s+([0-9]+)\\b",
+                "\\b" + name + "\\s*=\\s*([0-9]+)\\b"
+        };
+        for (String pattern : patterns) {
+            Matcher matcher = Pattern.compile(pattern).matcher(cfg);
+            if (matcher.find()) {
+                return Integer.parseInt(matcher.group(1));
+            }
+        }
+        throw new IOException("Unable to parse " + name);
+    }
+
+    @Override
+    public void setSize(Size size) throws IOException {
+        if (system) {
+            exec(true,
+                 OSUtils.STTY_COMMAND,
+                 "columns", Integer.toString(size.getColumns()),
+                 "rows", Integer.toString(size.getRows()));
+        } else {
+            exec(false,
+                 OSUtils.STTY_COMMAND,
+                 OSUtils.STTY_F_OPTION, getName(),
+                 "columns", Integer.toString(size.getColumns()),
+                 "rows", Integer.toString(size.getRows()));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ExecPty[" + getName() + (system ? ", system]" : "]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/ExternalTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.Cursor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.IntConsumer;
+
+/**
+ * Console implementation with embedded line disciplined.
+ *
+ * This terminal is well-suited for supporting incoming external
+ * connections, such as from the network (through telnet, ssh,
+ * or any kind of protocol).
+ * The terminal will start consuming the input in a separate thread
+ * to generate interruption events.
+ *
+ * @see LineDisciplineTerminal
+ */
+public class ExternalTerminal extends LineDisciplineTerminal {
+
+    protected final AtomicBoolean closed = new AtomicBoolean();
+    protected final InputStream masterInput;
+    protected final Object lock = new Object();
+    protected boolean paused = true;
+    protected Thread pumpThread;
+
+    public ExternalTerminal(String name, String type,
+                            InputStream masterInput,
+                            OutputStream masterOutput,
+                            Charset encoding) throws IOException {
+        this(name, type, masterInput, masterOutput, encoding, SignalHandler.SIG_DFL);
+    }
+
+    public ExternalTerminal(String name, String type,
+                            InputStream masterInput,
+                            OutputStream masterOutput,
+                            Charset encoding,
+                            SignalHandler signalHandler) throws IOException {
+        this(name, type, masterInput, masterOutput, encoding, signalHandler, false);
+    }
+
+    public ExternalTerminal(String name, String type,
+                            InputStream masterInput,
+                            OutputStream masterOutput,
+                            Charset encoding,
+                            SignalHandler signalHandler,
+                            boolean paused) throws IOException {
+        super(name, type, masterOutput, encoding, signalHandler);
+        this.masterInput = masterInput;
+        if (!paused) {
+            resume();
+        }
+    }
+
+    public void close() throws IOException {
+        if (closed.compareAndSet(false, true)) {
+            pause();
+            super.close();
+        }
+    }
+
+    @Override
+    public boolean canPauseResume() {
+        return true;
+    }
+
+    @Override
+    public void pause() {
+        synchronized (lock) {
+            paused = true;
+        }
+    }
+
+    @Override
+    public void pause(boolean wait) throws InterruptedException {
+        Thread p;
+        synchronized (lock) {
+            paused = true;
+            p = pumpThread;
+        }
+        if (p != null) {
+            p.interrupt();
+            p.join();
+        }
+    }
+
+    @Override
+    public void resume() {
+        synchronized (lock) {
+            paused = false;
+            if (pumpThread == null) {
+                pumpThread = new Thread(this::pump, toString() + " input pump thread");
+                pumpThread.setDaemon(true);
+                pumpThread.start();
+            }
+        }
+    }
+
+    @Override
+    public boolean paused() {
+        synchronized (lock) {
+            return paused;
+        }
+    }
+
+    public void pump() {
+        try {
+            byte[] buf = new byte[1024];
+            while (true) {
+                int c = masterInput.read(buf);
+                if (c >= 0) {
+                    processInputBytes(buf, 0, c);
+                }
+                if (c < 0 || closed.get()) {
+                    break;
+                }
+                synchronized (lock) {
+                    if (paused) {
+                        pumpThread = null;
+                        return;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            processIOException(e);
+        } finally {
+            synchronized (lock) {
+                pumpThread = null;
+            }
+        }
+        try {
+            slaveInput.close();
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    @Override
+    public Cursor getCursorPosition(IntConsumer discarded) {
+        return CursorSupport.getCursorPosition(this, discarded);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/LineDisciplineTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.Objects;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Attributes.ControlChar;
+import jdk.internal.org.jline.terminal.Attributes.InputFlag;
+import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
+import jdk.internal.org.jline.terminal.Attributes.OutputFlag;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.NonBlocking;
+import jdk.internal.org.jline.utils.NonBlockingPumpInputStream;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+
+/**
+ * Abstract terminal with support for line discipline.
+ * The {@link Terminal} interface represents the slave
+ * side of a PTY, but implementations derived from this class
+ * will handle both the slave and master side of things.
+ *
+ * In order to correctly handle line discipline, the terminal
+ * needs to read the input in advance in order to raise the
+ * signals as fast as possible.
+ * For example, when the user hits Ctrl+C, we can't wait until
+ * the application consumes all the read events.
+ * The same applies to echoing, when enabled, as the echoing
+ * has to happen as soon as the user hit the keyboard, and not
+ * only when the application running in the terminal processes
+ * the input.
+ */
+public class LineDisciplineTerminal extends AbstractTerminal {
+
+    private static final String DEFAULT_TERMINAL_ATTRIBUTES =
+                    "speed 9600 baud; 24 rows; 80 columns;\n" +
+                    "lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl\n" +
+                    "\t-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
+                    "\t-extproc\n" +
+                    "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8\n" +
+                    "\t-ignbrk brkint -inpck -ignpar -parmrk\n" +
+                    "oflags: opost onlcr -oxtabs -onocr -onlret\n" +
+                    "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
+                    "\t-dtrflow -mdmbuf\n" +
+                    "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
+                    "\teol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
+                    "\tmin = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
+                    "\tstop = ^S; susp = ^Z; time = 0; werase = ^W;\n";
+
+    private static final int PIPE_SIZE = 1024;
+
+    /*
+     * Master output stream
+     */
+    protected final OutputStream masterOutput;
+
+    /*
+     * Slave input pipe write side
+     */
+    protected final OutputStream slaveInputPipe;
+
+    /*
+     * Slave streams
+     */
+    protected final NonBlockingPumpInputStream slaveInput;
+    protected final NonBlockingReader slaveReader;
+    protected final PrintWriter slaveWriter;
+    protected final OutputStream slaveOutput;
+
+    /**
+     * Console data
+     */
+    protected final Attributes attributes;
+    protected final Size size;
+
+    public LineDisciplineTerminal(String name,
+                                  String type,
+                                  OutputStream masterOutput,
+                                  Charset encoding) throws IOException {
+        this(name, type, masterOutput, encoding, SignalHandler.SIG_DFL);
+    }
+
+    public LineDisciplineTerminal(String name,
+                                  String type,
+                                  OutputStream masterOutput,
+                                  Charset encoding,
+                                  SignalHandler signalHandler) throws IOException {
+        super(name, type, encoding, signalHandler);
+        NonBlockingPumpInputStream input = NonBlocking.nonBlockingPumpInputStream(PIPE_SIZE);
+        this.slaveInputPipe = input.getOutputStream();
+        this.slaveInput = input;
+        this.slaveReader = NonBlocking.nonBlocking(getName(), slaveInput, encoding());
+        this.slaveOutput = new FilteringOutputStream();
+        this.slaveWriter = new PrintWriter(new OutputStreamWriter(slaveOutput, encoding()));
+        this.masterOutput = masterOutput;
+        this.attributes = ExecPty.doGetAttr(DEFAULT_TERMINAL_ATTRIBUTES);
+        this.size = new Size(160, 50);
+        parseInfoCmp();
+    }
+
+    public NonBlockingReader reader() {
+        return slaveReader;
+    }
+
+    public PrintWriter writer() {
+        return slaveWriter;
+    }
+
+    @Override
+    public InputStream input() {
+        return slaveInput;
+    }
+
+    @Override
+    public OutputStream output() {
+        return slaveOutput;
+    }
+
+    public Attributes getAttributes() {
+        Attributes attr = new Attributes();
+        attr.copy(attributes);
+        return attr;
+    }
+
+    public void setAttributes(Attributes attr) {
+        attributes.copy(attr);
+    }
+
+    public Size getSize() {
+        Size sz = new Size();
+        sz.copy(size);
+        return sz;
+    }
+
+    public void setSize(Size sz) {
+        size.copy(sz);
+    }
+
+   @Override
+    public void raise(Signal signal) {
+       Objects.requireNonNull(signal);
+        // Do not call clear() atm as this can cause
+        // deadlock between reading / writing threads
+        // TODO: any way to fix that ?
+        /*
+        if (!attributes.getLocalFlag(LocalFlag.NOFLSH)) {
+            try {
+                slaveReader.clear();
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+        */
+        echoSignal(signal);
+        super.raise(signal);
+    }
+
+    /**
+     * Master input processing.
+     * All data coming to the terminal should be provided
+     * using this method.
+     *
+     * @param c the input byte
+     * @throws IOException if anything wrong happens
+     */
+    public void processInputByte(int c) throws IOException {
+        boolean flushOut = doProcessInputByte(c);
+        slaveInputPipe.flush();
+        if (flushOut) {
+            masterOutput.flush();
+        }
+    }
+
+    public void processInputBytes(byte[] input) throws IOException {
+        processInputBytes(input, 0, input.length);
+    }
+
+    public void processInputBytes(byte[] input, int offset, int length) throws IOException {
+        boolean flushOut = false;
+        for (int i = 0; i < length; i++) {
+            flushOut |= doProcessInputByte(input[offset + i]);
+        }
+        slaveInputPipe.flush();
+        if (flushOut) {
+            masterOutput.flush();
+        }
+    }
+
+    protected boolean doProcessInputByte(int c) throws IOException {
+        if (attributes.getLocalFlag(LocalFlag.ISIG)) {
+            if (c == attributes.getControlChar(ControlChar.VINTR)) {
+                raise(Signal.INT);
+                return false;
+            } else if (c == attributes.getControlChar(ControlChar.VQUIT)) {
+                raise(Signal.QUIT);
+                return false;
+            } else if (c == attributes.getControlChar(ControlChar.VSUSP)) {
+                raise(Signal.TSTP);
+                return false;
+            } else if (c == attributes.getControlChar(ControlChar.VSTATUS)) {
+                raise(Signal.INFO);
+            }
+        }
+        if (c == '\r') {
+            if (attributes.getInputFlag(InputFlag.IGNCR)) {
+                return false;
+            }
+            if (attributes.getInputFlag(InputFlag.ICRNL)) {
+                c = '\n';
+            }
+        } else if (c == '\n' && attributes.getInputFlag(InputFlag.INLCR)) {
+            c = '\r';
+        }
+        boolean flushOut = false;
+        if (attributes.getLocalFlag(LocalFlag.ECHO)) {
+            processOutputByte(c);
+            flushOut = true;
+        }
+        slaveInputPipe.write(c);
+        return flushOut;
+    }
+
+    /**
+     * Master output processing.
+     * All data going to the master should be provided by this method.
+     *
+     * @param c the output byte
+     * @throws IOException if anything wrong happens
+     */
+    protected void processOutputByte(int c) throws IOException {
+        if (attributes.getOutputFlag(OutputFlag.OPOST)) {
+            if (c == '\n') {
+                if (attributes.getOutputFlag(OutputFlag.ONLCR)) {
+                    masterOutput.write('\r');
+                    masterOutput.write('\n');
+                    return;
+                }
+            }
+        }
+        masterOutput.write(c);
+    }
+
+    protected void processIOException(IOException ioException) {
+        this.slaveInput.setIoException(ioException);
+    }
+
+    public void close() throws IOException {
+        super.close();
+        try {
+            slaveReader.close();
+        } finally {
+            try {
+                slaveInputPipe.close();
+            } finally {
+                try {
+                } finally {
+                    slaveWriter.close();
+                }
+            }
+        }
+    }
+
+    private class FilteringOutputStream extends OutputStream {
+        @Override
+        public void write(int b) throws IOException {
+            processOutputByte(b);
+            flush();
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            if (b == null) {
+                throw new NullPointerException();
+            } else if ((off < 0) || (off > b.length) || (len < 0) ||
+                    ((off + len) > b.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return;
+            }
+            for (int i = 0 ; i < len ; i++) {
+                processOutputByte(b[off + i]);
+            }
+            flush();
+        }
+
+        @Override
+        public void flush() throws IOException {
+            masterOutput.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            masterOutput.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/MouseSupport.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,138 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.MouseEvent;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.InfoCmp;
+import jdk.internal.org.jline.utils.InputStreamReader;
+
+import java.io.EOFException;
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.EnumSet;
+import java.util.function.IntSupplier;
+
+public class MouseSupport {
+
+    public static boolean hasMouseSupport(Terminal terminal) {
+        return terminal.getStringCapability(InfoCmp.Capability.key_mouse) != null;
+    }
+
+    public static boolean trackMouse(Terminal terminal, Terminal.MouseTracking tracking) {
+        if (hasMouseSupport(terminal)) {
+            switch (tracking) {
+                case Off:
+                    terminal.writer().write("\033[?1000l");
+                    break;
+                case Normal:
+                    terminal.writer().write("\033[?1005h\033[?1000h");
+                    break;
+                case Button:
+                    terminal.writer().write("\033[?1005h\033[?1002h");
+                    break;
+                case Any:
+                    terminal.writer().write("\033[?1005h\033[?1003h");
+                    break;
+            }
+            terminal.flush();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static MouseEvent readMouse(Terminal terminal, MouseEvent last) {
+        return readMouse(() -> readExt(terminal), last);
+    }
+
+    public static MouseEvent readMouse(IntSupplier reader, MouseEvent last) {
+        int cb = reader.getAsInt() - ' ';
+        int cx = reader.getAsInt() - ' ' - 1;
+        int cy = reader.getAsInt() - ' ' - 1;
+        MouseEvent.Type type;
+        MouseEvent.Button button;
+        EnumSet<MouseEvent.Modifier> modifiers = EnumSet.noneOf(MouseEvent.Modifier.class);
+        if ((cb & 4) == 4) {
+            modifiers.add(MouseEvent.Modifier.Shift);
+        }
+        if ((cb & 8) == 8) {
+            modifiers.add(MouseEvent.Modifier.Alt);
+        }
+        if ((cb & 16) == 16) {
+            modifiers.add(MouseEvent.Modifier.Control);
+        }
+        if ((cb & 64) == 64) {
+            type = MouseEvent.Type.Wheel;
+            button = (cb & 1) == 1 ? MouseEvent.Button.WheelDown : MouseEvent.Button.WheelUp;
+        } else {
+            int b = (cb & 3);
+            switch (b) {
+                case 0:
+                    button = MouseEvent.Button.Button1;
+                    if (last.getButton() == button
+                            && (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
+                        type = MouseEvent.Type.Dragged;
+                    } else {
+                        type = MouseEvent.Type.Pressed;
+                    }
+                    break;
+                case 1:
+                    button = MouseEvent.Button.Button2;
+                    if (last.getButton() == button
+                            && (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
+                        type = MouseEvent.Type.Dragged;
+                    } else {
+                        type = MouseEvent.Type.Pressed;
+                    }
+                    break;
+                case 2:
+                    button = MouseEvent.Button.Button3;
+                    if (last.getButton() == button
+                            && (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged)) {
+                        type = MouseEvent.Type.Dragged;
+                    } else {
+                        type = MouseEvent.Type.Pressed;
+                    }
+                    break;
+                default:
+                    if (last.getType() == MouseEvent.Type.Pressed || last.getType() == MouseEvent.Type.Dragged) {
+                        button = last.getButton();
+                        type = MouseEvent.Type.Released;
+                    } else {
+                        button = MouseEvent.Button.NoButton;
+                        type = MouseEvent.Type.Moved;
+                    }
+                    break;
+            }
+        }
+        return new MouseEvent(type, button, modifiers, cx, cy);
+    }
+
+    private static int readExt(Terminal terminal) {
+        try {
+            // The coordinates are encoded in UTF-8, so if that's not the input encoding,
+            // we need to get around
+            int c;
+            if (terminal.encoding() != StandardCharsets.UTF_8) {
+                c = new InputStreamReader(terminal.input(), StandardCharsets.UTF_8).read();
+            } else {
+                c = terminal.reader().read();
+            }
+            if (c < 0) {
+                throw new EOFException();
+            }
+            return c;
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/NativeSignalHandler.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import jdk.internal.org.jline.terminal.Terminal.Signal;
+import jdk.internal.org.jline.terminal.Terminal.SignalHandler;
+
+public final class NativeSignalHandler implements SignalHandler {
+
+    public static final NativeSignalHandler SIG_DFL = new NativeSignalHandler();
+
+    public static final NativeSignalHandler SIG_IGN = new NativeSignalHandler();
+
+    private NativeSignalHandler() {
+    }
+
+    public void handle(Signal signal) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixPtyTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import jdk.internal.org.jline.terminal.spi.Pty;
+import jdk.internal.org.jline.utils.ClosedException;
+import jdk.internal.org.jline.utils.NonBlocking;
+import jdk.internal.org.jline.utils.NonBlockingInputStream;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+
+public class PosixPtyTerminal extends AbstractPosixTerminal {
+
+    private final InputStream in;
+    private final OutputStream out;
+    private final InputStream masterInput;
+    private final OutputStream masterOutput;
+    private final NonBlockingInputStream input;
+    private final OutputStream output;
+    private final NonBlockingReader reader;
+    private final PrintWriter writer;
+
+    private final Object lock = new Object();
+    private Thread inputPumpThread;
+    private Thread outputPumpThread;
+    private boolean paused = true;
+
+    public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding) throws IOException {
+        this(name, type, pty, in, out, encoding, SignalHandler.SIG_DFL);
+    }
+
+    public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler) throws IOException {
+        this(name, type, pty, in, out, encoding, signalHandler, false);
+    }
+
+    public PosixPtyTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding, SignalHandler signalHandler, boolean paused) throws IOException {
+        super(name, type, pty, encoding, signalHandler);
+        this.in = Objects.requireNonNull(in);
+        this.out = Objects.requireNonNull(out);
+        this.masterInput = pty.getMasterInput();
+        this.masterOutput = pty.getMasterOutput();
+        this.input = new InputStreamWrapper(NonBlocking.nonBlocking(name, pty.getSlaveInput()));
+        this.output = pty.getSlaveOutput();
+        this.reader = NonBlocking.nonBlocking(name, input, encoding());
+        this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
+        parseInfoCmp();
+        if (!paused) {
+            resume();
+        }
+    }
+
+    public InputStream input() {
+        return input;
+    }
+
+    public NonBlockingReader reader() {
+        return reader;
+    }
+
+    public OutputStream output() {
+        return output;
+    }
+
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        reader.close();
+    }
+
+    @Override
+    public boolean canPauseResume() {
+        return true;
+    }
+
+    @Override
+    public void pause() {
+        synchronized (lock) {
+            paused = true;
+        }
+    }
+
+    @Override
+    public void pause(boolean wait) throws InterruptedException {
+        Thread p1, p2;
+        synchronized (lock) {
+            paused = true;
+            p1 = inputPumpThread;
+            p2 = outputPumpThread;
+        }
+        if (p1 != null) {
+            p1.interrupt();
+        }
+        if (p2 != null) {
+            p2.interrupt();
+        }
+        if (p1 != null) {
+            p1.join();
+        }
+        if (p2 !=null) {
+            p2.join();
+        }
+    }
+
+    @Override
+    public void resume() {
+        synchronized (lock) {
+            paused = false;
+            if (inputPumpThread == null) {
+                inputPumpThread = new Thread(this::pumpIn, toString() + " input pump thread");
+                inputPumpThread.setDaemon(true);
+                inputPumpThread.start();
+            }
+            if (outputPumpThread == null) {
+                outputPumpThread = new Thread(this::pumpOut, toString() + " output pump thread");
+                outputPumpThread.setDaemon(true);
+                outputPumpThread.start();
+            }
+        }
+    }
+
+    @Override
+    public boolean paused() {
+        synchronized (lock) {
+            return paused;
+        }
+    }
+
+    private class InputStreamWrapper extends NonBlockingInputStream {
+
+        private final NonBlockingInputStream in;
+        private final AtomicBoolean closed = new AtomicBoolean();
+
+        protected InputStreamWrapper(NonBlockingInputStream in) {
+            this.in = in;
+        }
+
+        @Override
+        public int read(long timeout, boolean isPeek) throws IOException {
+            if (closed.get()) {
+                throw new ClosedException();
+            }
+            return in.read(timeout, isPeek);
+        }
+
+        @Override
+        public void close() throws IOException {
+            closed.set(true);
+        }
+    }
+
+    private void pumpIn() {
+        try {
+            for (;;) {
+                synchronized (lock) {
+                    if (paused) {
+                        inputPumpThread = null;
+                        return;
+                    }
+                }
+                int b = in.read();
+                if (b < 0) {
+                    input.close();
+                    break;
+                }
+                masterOutput.write(b);
+                masterOutput.flush();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            synchronized (lock) {
+                inputPumpThread = null;
+            }
+        }
+    }
+
+    private void pumpOut() {
+        try {
+            for (;;) {
+                synchronized (lock) {
+                    if (paused) {
+                        outputPumpThread = null;
+                        return;
+                    }
+                }
+                int b = masterInput.read();
+                if (b < 0) {
+                    input.close();
+                    break;
+                }
+                out.write(b);
+                out.flush();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            synchronized (lock) {
+                outputPumpThread = null;
+            }
+        }
+        try {
+            close();
+        } catch (Throwable t) {
+            // Ignore
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/PosixSysTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import jdk.internal.org.jline.utils.NonBlocking;
+import jdk.internal.org.jline.terminal.spi.Pty;
+import jdk.internal.org.jline.utils.NonBlockingInputStream;
+import jdk.internal.org.jline.utils.NonBlockingReader;
+import jdk.internal.org.jline.utils.ShutdownHooks;
+import jdk.internal.org.jline.utils.ShutdownHooks.Task;
+import jdk.internal.org.jline.utils.Signals;
+
+public class PosixSysTerminal extends AbstractPosixTerminal {
+
+    protected final NonBlockingInputStream input;
+    protected final OutputStream output;
+    protected final NonBlockingReader reader;
+    protected final PrintWriter writer;
+    protected final Map<Signal, Object> nativeHandlers = new HashMap<>();
+    protected final Task closer;
+
+    public PosixSysTerminal(String name, String type, Pty pty, InputStream in, OutputStream out, Charset encoding,
+                            boolean nativeSignals, SignalHandler signalHandler) throws IOException {
+        super(name, type, pty, encoding, signalHandler);
+        this.input = NonBlocking.nonBlocking(getName(), in);
+        this.output = out;
+        this.reader = NonBlocking.nonBlocking(getName(), input, encoding());
+        this.writer = new PrintWriter(new OutputStreamWriter(output, encoding()));
+        parseInfoCmp();
+        if (nativeSignals) {
+            for (final Signal signal : Signal.values()) {
+                if (signalHandler == SignalHandler.SIG_DFL) {
+                    nativeHandlers.put(signal, Signals.registerDefault(signal.name()));
+                } else {
+                    nativeHandlers.put(signal, Signals.register(signal.name(), () -> raise(signal)));
+                }
+            }
+        }
+        closer = PosixSysTerminal.this::close;
+        ShutdownHooks.add(closer);
+    }
+
+    @Override
+    public SignalHandler handle(Signal signal, SignalHandler handler) {
+        SignalHandler prev = super.handle(signal, handler);
+        if (prev != handler) {
+            if (handler == SignalHandler.SIG_DFL) {
+                Signals.registerDefault(signal.name());
+            } else {
+                Signals.register(signal.name(), () -> raise(signal));
+            }
+        }
+        return prev;
+    }
+
+    public NonBlockingReader reader() {
+        return reader;
+    }
+
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public InputStream input() {
+        return input;
+    }
+
+    @Override
+    public OutputStream output() {
+        return output;
+    }
+
+    @Override
+    public void close() throws IOException {
+        ShutdownHooks.remove(closer);
+        for (Map.Entry<Signal, Object> entry : nativeHandlers.entrySet()) {
+            Signals.unregister(entry.getKey().name(), entry.getValue());
+        }
+        super.close();
+        // Do not call reader.close()
+        reader.shutdown();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/package-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,14 @@
+/*
+ * 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
+ */
+/**
+ * JLine 3.
+ *
+ * @since 3.0
+ */
+package jdk.internal.org.jline.terminal.impl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,20 @@
+package jdk.internal.org.jline.terminal.spi;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+public interface JansiSupport {
+
+    Pty current() throws IOException;
+
+    Pty open(Attributes attributes, Size size) throws IOException;
+
+    Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException;
+
+    Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,24 @@
+package jdk.internal.org.jline.terminal.spi;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.function.Function;
+
+public interface JnaSupport {
+
+    Pty current() throws IOException;
+
+    Pty open(Attributes attributes, Size size) throws IOException;
+
+    Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException;
+
+    Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException;
+
+    Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/Pty.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.spi;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Size;
+
+public interface Pty extends Closeable {
+
+    InputStream getMasterInput() throws IOException;
+
+    OutputStream getMasterOutput() throws IOException;
+
+    InputStream getSlaveInput() throws IOException;
+
+    OutputStream getSlaveOutput() throws IOException;
+
+    Attributes getAttr() throws IOException;
+
+    void setAttr(Attributes attr) throws IOException;
+
+    Size getSize() throws IOException;
+
+    void setSize(Size size) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AnsiWriter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2009-2018 the original author(s).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * A ANSI writer extracts ANSI escape codes written to
+ * a {@link Writer} and calls corresponding <code>process*</code> methods.
+ *
+ * For more information about ANSI escape codes, see:
+ * http://en.wikipedia.org/wiki/ANSI_escape_code
+ *
+ * This class just filters out the escape codes so that they are not
+ * sent out to the underlying {@link Writer}: <code>process*</code> methods
+ * are empty. Subclasses should actually perform the ANSI escape behaviors
+ * by implementing active code in <code>process*</code> methods.
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ * @author Joris Kuipers
+ * @since 1.0
+ */
+public class AnsiWriter extends FilterWriter {
+
+    private static final char[] RESET_CODE = "\033[0m".toCharArray();
+
+    public AnsiWriter(Writer out) {
+        super(out);
+    }
+
+    private final static int MAX_ESCAPE_SEQUENCE_LENGTH = 100;
+    private final char[] buffer = new char[MAX_ESCAPE_SEQUENCE_LENGTH];
+    private int pos = 0;
+    private int startOfValue;
+    private final ArrayList<Object> options = new ArrayList<>();
+
+    private static final int LOOKING_FOR_FIRST_ESC_CHAR = 0;
+    private static final int LOOKING_FOR_SECOND_ESC_CHAR = 1;
+    private static final int LOOKING_FOR_NEXT_ARG = 2;
+    private static final int LOOKING_FOR_STR_ARG_END = 3;
+    private static final int LOOKING_FOR_INT_ARG_END = 4;
+    private static final int LOOKING_FOR_OSC_COMMAND = 5;
+    private static final int LOOKING_FOR_OSC_COMMAND_END = 6;
+    private static final int LOOKING_FOR_OSC_PARAM = 7;
+    private static final int LOOKING_FOR_ST = 8;
+    private static final int LOOKING_FOR_CHARSET = 9;
+
+    int state = LOOKING_FOR_FIRST_ESC_CHAR;
+
+    private static final int FIRST_ESC_CHAR = 27;
+    private static final int SECOND_ESC_CHAR = '[';
+    private static final int SECOND_OSC_CHAR = ']';
+    private static final int BEL = 7;
+    private static final int SECOND_ST_CHAR = '\\';
+    private static final int SECOND_CHARSET0_CHAR = '(';
+    private static final int SECOND_CHARSET1_CHAR = ')';
+
+    @Override
+    public synchronized void write(int data) throws IOException {
+        switch (state) {
+            case LOOKING_FOR_FIRST_ESC_CHAR:
+                if (data == FIRST_ESC_CHAR) {
+                    buffer[pos++] = (char) data;
+                    state = LOOKING_FOR_SECOND_ESC_CHAR;
+                } else {
+                    out.write(data);
+                }
+                break;
+
+            case LOOKING_FOR_SECOND_ESC_CHAR:
+                buffer[pos++] = (char) data;
+                if (data == SECOND_ESC_CHAR) {
+                    state = LOOKING_FOR_NEXT_ARG;
+                } else if (data == SECOND_OSC_CHAR) {
+                    state = LOOKING_FOR_OSC_COMMAND;
+                } else if (data == SECOND_CHARSET0_CHAR) {
+                    options.add((int) '0');
+                    state = LOOKING_FOR_CHARSET;
+                } else if (data == SECOND_CHARSET1_CHAR) {
+                    options.add((int) '1');
+                    state = LOOKING_FOR_CHARSET;
+                } else {
+                    reset(false);
+                }
+                break;
+
+            case LOOKING_FOR_NEXT_ARG:
+                buffer[pos++] = (char) data;
+                if ('"' == data) {
+                    startOfValue = pos - 1;
+                    state = LOOKING_FOR_STR_ARG_END;
+                } else if ('0' <= data && data <= '9') {
+                    startOfValue = pos - 1;
+                    state = LOOKING_FOR_INT_ARG_END;
+                } else if (';' == data) {
+                    options.add(null);
+                } else if ('?' == data) {
+                    options.add('?');
+                } else if ('=' == data) {
+                    options.add('=');
+                } else {
+                    boolean skip = true;
+                    try {
+                        skip = processEscapeCommand(options, data);
+                    } finally {
+                        reset(skip);
+                    }
+                }
+                break;
+            default:
+                break;
+
+            case LOOKING_FOR_INT_ARG_END:
+                buffer[pos++] = (char) data;
+                if (!('0' <= data && data <= '9')) {
+                    String strValue = new String(buffer, startOfValue, (pos - 1) - startOfValue);
+                    Integer value = Integer.valueOf(strValue);
+                    options.add(value);
+                    if (data == ';') {
+                        state = LOOKING_FOR_NEXT_ARG;
+                    } else {
+                        boolean skip = true;
+                        try {
+                            skip = processEscapeCommand(options, data);
+                        } finally {
+                            reset(skip);
+                        }
+                    }
+                }
+                break;
+
+            case LOOKING_FOR_STR_ARG_END:
+                buffer[pos++] = (char) data;
+                if ('"' != data) {
+                    String value = new String(buffer, startOfValue, (pos - 1) - startOfValue);
+                    options.add(value);
+                    if (data == ';') {
+                        state = LOOKING_FOR_NEXT_ARG;
+                    } else {
+                        reset(processEscapeCommand(options, data));
+                    }
+                }
+                break;
+
+            case LOOKING_FOR_OSC_COMMAND:
+                buffer[pos++] = (char) data;
+                if ('0' <= data && data <= '9') {
+                    startOfValue = pos - 1;
+                    state = LOOKING_FOR_OSC_COMMAND_END;
+                } else {
+                    reset(false);
+                }
+                break;
+
+            case LOOKING_FOR_OSC_COMMAND_END:
+                buffer[pos++] = (char) data;
+                if (';' == data) {
+                    String strValue = new String(buffer, startOfValue, (pos - 1) - startOfValue);
+                    Integer value = Integer.valueOf(strValue);
+                    options.add(value);
+                    startOfValue = pos;
+                    state = LOOKING_FOR_OSC_PARAM;
+                } else if ('0' <= data && data <= '9') {
+                    // already pushed digit to buffer, just keep looking
+                } else {
+                    // oops, did not expect this
+                    reset(false);
+                }
+                break;
+
+            case LOOKING_FOR_OSC_PARAM:
+                buffer[pos++] = (char) data;
+                if (BEL == data) {
+                    String value = new String(buffer, startOfValue, (pos - 1) - startOfValue);
+                    options.add(value);
+                    boolean skip = true;
+                    try {
+                        skip = processOperatingSystemCommand(options);
+                    } finally {
+                        reset(skip);
+                    }
+                } else if (FIRST_ESC_CHAR == data) {
+                    state = LOOKING_FOR_ST;
+                } else {
+                    // just keep looking while adding text
+                }
+                break;
+
+            case LOOKING_FOR_ST:
+                buffer[pos++] = (char) data;
+                if (SECOND_ST_CHAR == data) {
+                    String value = new String(buffer, startOfValue, (pos - 2) - startOfValue);
+                    options.add(value);
+                    boolean skip = true;
+                    try {
+                        skip = processOperatingSystemCommand(options);
+                    } finally {
+                        reset(skip);
+                    }
+                } else {
+                    state = LOOKING_FOR_OSC_PARAM;
+                }
+                break;
+
+            case LOOKING_FOR_CHARSET:
+                options.add((char) data);
+                reset(processCharsetSelect(options));
+                break;
+        }
+
+        // Is it just too long?
+        if (pos >= buffer.length) {
+            reset(false);
+        }
+    }
+
+    /**
+     * Resets all state to continue with regular parsing
+     * @param skipBuffer if current buffer should be skipped or written to out
+     * @throws IOException if an error occurs
+     */
+    private void reset(boolean skipBuffer) throws IOException {
+        if (!skipBuffer) {
+            out.write(buffer, 0, pos);
+        }
+        pos = 0;
+        startOfValue = 0;
+        options.clear();
+        state = LOOKING_FOR_FIRST_ESC_CHAR;
+    }
+
+    /**
+     * Helper for processEscapeCommand() to iterate over integer options
+     * @param  optionsIterator  the underlying iterator
+     * @throws IOException      if no more non-null values left
+     */
+    private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException {
+        for (;;) {
+            if (!optionsIterator.hasNext())
+                throw new IllegalArgumentException();
+            Object arg = optionsIterator.next();
+            if (arg != null)
+                return (Integer) arg;
+        }
+    }
+
+    /**
+     * Process escape command
+     * @param options the list of options
+     * @param command the command
+     * @throws IOException if an error occurs
+     * @return true if the escape command was processed.
+     */
+    private boolean processEscapeCommand(ArrayList<Object> options, int command) throws IOException {
+        try {
+            switch (command) {
+                case 'A':
+                    processCursorUp(optionInt(options, 0, 1));
+                    return true;
+                case 'B':
+                    processCursorDown(optionInt(options, 0, 1));
+                    return true;
+                case 'C':
+                    processCursorRight(optionInt(options, 0, 1));
+                    return true;
+                case 'D':
+                    processCursorLeft(optionInt(options, 0, 1));
+                    return true;
+                case 'E':
+                    processCursorDownLine(optionInt(options, 0, 1));
+                    return true;
+                case 'F':
+                    processCursorUpLine(optionInt(options, 0, 1));
+                    return true;
+                case 'G':
+                    processCursorToColumn(optionInt(options, 0));
+                    return true;
+                case 'H':
+                case 'f':
+                    processCursorTo(optionInt(options, 0, 1), optionInt(options, 1, 1));
+                    return true;
+                case 'J':
+                    processEraseScreen(optionInt(options, 0, 0));
+                    return true;
+                case 'K':
+                    processEraseLine(optionInt(options, 0, 0));
+                    return true;
+                case 'L':
+                    processInsertLine(optionInt(options, 0, 1));
+                    return true;
+                case 'M':
+                    processDeleteLine(optionInt(options, 0, 1));
+                    return true;
+                case 'S':
+                    processScrollUp(optionInt(options, 0, 1));
+                    return true;
+                case 'T':
+                    processScrollDown(optionInt(options, 0, 1));
+                    return true;
+                case 'm':
+                    // Validate all options are ints...
+                    for (Object next : options) {
+                        if (next != null && next.getClass() != Integer.class) {
+                            throw new IllegalArgumentException();
+                        }
+                    }
+
+                    int count = 0;
+                    Iterator<Object> optionsIterator = options.iterator();
+                    while (optionsIterator.hasNext()) {
+                        Object next = optionsIterator.next();
+                        if (next != null) {
+                            count++;
+                            int value = (Integer) next;
+                            if (30 <= value && value <= 37) {
+                                processSetForegroundColor(value - 30);
+                            } else if (40 <= value && value <= 47) {
+                                processSetBackgroundColor(value - 40);
+                            } else if (90 <= value && value <= 97) {
+                                processSetForegroundColor(value - 90, true);
+                            } else if (100 <= value && value <= 107) {
+                                processSetBackgroundColor(value - 100, true);
+                            } else if (value == 38 || value == 48) {
+                                // extended color like `esc[38;5;<index>m` or `esc[38;2;<r>;<g>;<b>m`
+                                int arg2or5 = getNextOptionInt(optionsIterator);
+                                if (arg2or5 == 2) {
+                                    // 24 bit color style like `esc[38;2;<r>;<g>;<b>m`
+                                    int r = getNextOptionInt(optionsIterator);
+                                    int g = getNextOptionInt(optionsIterator);
+                                    int b = getNextOptionInt(optionsIterator);
+                                    if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
+                                        if (value == 38)
+                                            processSetForegroundColorExt(r, g, b);
+                                        else
+                                            processSetBackgroundColorExt(r, g, b);
+                                    } else {
+                                        throw new IllegalArgumentException();
+                                    }
+                                }
+                                else if (arg2or5 == 5) {
+                                    // 256 color style like `esc[38;5;<index>m`
+                                    int paletteIndex = getNextOptionInt(optionsIterator);
+                                    if (paletteIndex >= 0 && paletteIndex <= 255) {
+                                        if (value == 38)
+                                            processSetForegroundColorExt(paletteIndex);
+                                        else
+                                            processSetBackgroundColorExt(paletteIndex);
+                                    } else {
+                                        throw new IllegalArgumentException();
+                                    }
+                                }
+                                else {
+                                    throw new IllegalArgumentException();
+                                }
+                            } else {
+                                switch (value) {
+                                    case 39:
+                                        processDefaultTextColor();
+                                        break;
+                                    case 49:
+                                        processDefaultBackgroundColor();
+                                        break;
+                                    case 0:
+                                        processAttributeRest();
+                                        break;
+                                    default:
+                                        processSetAttribute(value);
+                                }
+                            }
+                        }
+                    }
+                    if (count == 0) {
+                        processAttributeRest();
+                    }
+                    return true;
+                case 's':
+                    processSaveCursorPosition();
+                    return true;
+                case 'u':
+                    processRestoreCursorPosition();
+                    return true;
+
+                default:
+                    if ('a' <= command && 'z' <= command) {
+                        processUnknownExtension(options, command);
+                        return true;
+                    }
+                    if ('A' <= command && 'Z' <= command) {
+                        processUnknownExtension(options, command);
+                        return true;
+                    }
+                    return false;
+            }
+        } catch (IllegalArgumentException ignore) {
+        }
+        return false;
+    }
+
+    /**
+     * Process operating system command.
+     * @param options the options list
+     * @return true if the operating system command was processed.
+     */
+    private boolean processOperatingSystemCommand(ArrayList<Object> options) throws IOException {
+        int command = optionInt(options, 0);
+        String label = (String) options.get(1);
+        // for command > 2 label could be composed (i.e. contain ';'), but we'll leave
+        // it to processUnknownOperatingSystemCommand implementations to handle that
+        try {
+            switch (command) {
+                case 0:
+                    processChangeIconNameAndWindowTitle(label);
+                    return true;
+                case 1:
+                    processChangeIconName(label);
+                    return true;
+                case 2:
+                    processChangeWindowTitle(label);
+                    return true;
+
+                default:
+                    // not exactly unknown, but not supported through dedicated process methods:
+                    processUnknownOperatingSystemCommand(command, label);
+                    return true;
+            }
+        } catch (IllegalArgumentException ignore) {
+        }
+        return false;
+    }
+
+    /**
+     * Process <code>CSI u</code> ANSI code, corresponding to <code>RCP \u2013 Restore Cursor Position</code>
+     * @throws IOException if an error occurs
+     */
+    protected void processRestoreCursorPosition() throws IOException {
+    }
+
+    /**
+     * Process <code>CSI s</code> ANSI code, corresponding to <code>SCP \u2013 Save Cursor Position</code>
+     * @throws IOException if an error occurs
+     */
+    protected void processSaveCursorPosition() throws IOException {
+    }
+
+    /**
+     * Process <code>CSI s</code> ANSI code, corresponding to <code>IL \u2013 Insert Line</code>
+     * @param optionInt the option
+     * @throws IOException if an error occurs
+     */
+    protected void processInsertLine(int optionInt) throws IOException {
+    }
+
+    /**
+     * Process <code>CSI s</code> ANSI code, corresponding to <code>DL \u2013 Delete Line</code>
+     * @param optionInt the option
+     * @throws IOException if an error occurs
+     */
+    protected void processDeleteLine(int optionInt) throws IOException {
+    }
+
+    /**
+     * Process <code>CSI n T</code> ANSI code, corresponding to <code>SD \u2013 Scroll Down</code>
+     * @param optionInt the option
+     * @throws IOException if an error occurs
+     */
+    protected void processScrollDown(int optionInt) throws IOException {
+    }
+
+    /**
+     * Process <code>CSI n U</code> ANSI code, corresponding to <code>SU \u2013 Scroll Up</code>
+     * @param optionInt the option
+     * @throws IOException if an error occurs
+     */
+    protected void processScrollUp(int optionInt) throws IOException {
+    }
+
+    protected static final int ERASE_SCREEN_TO_END = 0;
+    protected static final int ERASE_SCREEN_TO_BEGINING = 1;
+    protected static final int ERASE_SCREEN = 2;
+
+    /**
+     * Process <code>CSI n J</code> ANSI code, corresponding to <code>ED \u2013 Erase in Display</code>
+     * @param eraseOption the erase option
+     * @throws IOException if an error occurs
+     */
+    protected void processEraseScreen(int eraseOption) throws IOException {
+    }
+
+    protected static final int ERASE_LINE_TO_END = 0;
+    protected static final int ERASE_LINE_TO_BEGINING = 1;
+    protected static final int ERASE_LINE = 2;
+
+    /**
+     * Process <code>CSI n K</code> ANSI code, corresponding to <code>ED \u2013 Erase in Line</code>
+     * @param eraseOption the erase option
+     * @throws IOException if an error occurs
+     */
+    protected void processEraseLine(int eraseOption) throws IOException {
+    }
+
+    protected static final int ATTRIBUTE_INTENSITY_BOLD = 1; //         Intensity: Bold
+    protected static final int ATTRIBUTE_INTENSITY_FAINT = 2; //        Intensity; Faint        not widely supported
+    protected static final int ATTRIBUTE_ITALIC = 3; //         Italic; on      not widely supported. Sometimes treated as inverse.
+    protected static final int ATTRIBUTE_UNDERLINE = 4; //      Underline; Single
+    protected static final int ATTRIBUTE_BLINK_SLOW = 5; //     Blink; Slow     less than 150 per minute
+    protected static final int ATTRIBUTE_BLINK_FAST = 6; //     Blink; Rapid    MS-DOS ANSI.SYS; 150 per minute or more
+    protected static final int ATTRIBUTE_NEGATIVE_ON = 7; //    Image; Negative         inverse or reverse; swap foreground and background
+    protected static final int ATTRIBUTE_CONCEAL_ON = 8; //     Conceal on
+    protected static final int ATTRIBUTE_UNDERLINE_DOUBLE = 21; //      Underline; Double       not widely supported
+    protected static final int ATTRIBUTE_INTENSITY_NORMAL = 22; //      Intensity; Normal       not bold and not faint
+    protected static final int ATTRIBUTE_UNDERLINE_OFF = 24; //         Underline; None
+    protected static final int ATTRIBUTE_BLINK_OFF = 25; //     Blink; off
+    @Deprecated
+    protected static final int ATTRIBUTE_NEGATIVE_Off = 27; //  Image; Positive
+    protected static final int ATTRIBUTE_NEGATIVE_OFF = 27; //  Image; Positive
+    protected static final int ATTRIBUTE_CONCEAL_OFF = 28; //   Reveal  conceal off
+
+    /**
+     * process <code>SGR</code> other than <code>0</code> (reset), <code>30-39</code> (foreground),
+     * <code>40-49</code> (background), <code>90-97</code> (foreground high intensity) or
+     * <code>100-107</code> (background high intensity)
+     * @param attribute the attribute to set
+     * @throws IOException if an error occurs
+     * @see #processAttributeRest()
+     * @see #processSetForegroundColor(int)
+     * @see #processSetForegroundColor(int, boolean)
+     * @see #processSetForegroundColorExt(int)
+     * @see #processSetForegroundColorExt(int, int, int)
+     * @see #processDefaultTextColor()
+     * @see #processDefaultBackgroundColor()
+     */
+    protected void processSetAttribute(int attribute) throws IOException {
+    }
+
+    protected static final int BLACK = 0;
+    protected static final int RED = 1;
+    protected static final int GREEN = 2;
+    protected static final int YELLOW = 3;
+    protected static final int BLUE = 4;
+    protected static final int MAGENTA = 5;
+    protected static final int CYAN = 6;
+    protected static final int WHITE = 7;
+
+    /**
+     * process <code>SGR 30-37</code> corresponding to <code>Set text color (foreground)</code>.
+     * @param color the text color
+     * @throws IOException if an error occurs
+     */
+    protected void processSetForegroundColor(int color) throws IOException {
+        processSetForegroundColor(color, false);
+    }
+
+    /**
+     * process <code>SGR 30-37</code> or <code>SGR 90-97</code> corresponding to
+     * <code>Set text color (foreground)</code> either in normal mode or high intensity.
+     * @param color the text color
+     * @param bright is high intensity?
+     * @throws IOException if an error occurs
+     */
+    protected void processSetForegroundColor(int color, boolean bright) throws IOException {
+        processSetForegroundColorExt(bright ? color + 8 : color);
+    }
+
+    /**
+     * process <code>SGR 38</code> corresponding to <code>extended set text color (foreground)</code>
+     * with a palette of 255 colors.
+     * @param paletteIndex the text color in the palette
+     * @throws IOException if an error occurs
+     */
+    protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
+    }
+
+    /**
+     * process <code>SGR 38</code> corresponding to <code>extended set text color (foreground)</code>
+     * with a 24 bits RGB definition of the color.
+     * @param r red
+     * @param g green
+     * @param b blue
+     * @throws IOException if an error occurs
+     */
+    protected void processSetForegroundColorExt(int r, int g, int b) throws IOException {
+        processSetForegroundColorExt(Colors.roundRgbColor(r, g, b, 16));
+    }
+
+    /**
+     * process <code>SGR 40-47</code> corresponding to <code>Set background color</code>.
+     * @param color the background color
+     * @throws IOException if an error occurs
+     */
+    protected void processSetBackgroundColor(int color) throws IOException {
+        processSetBackgroundColor(color, false);
+    }
+
+    /**
+     * process <code>SGR 40-47</code> or <code>SGR 100-107</code> corresponding to
+     * <code>Set background color</code> either in normal mode or high intensity.
+     * @param color the background color
+     * @param bright is high intensity?
+     * @throws IOException if an error occurs
+     */
+    protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
+        processSetBackgroundColorExt(bright ? color + 8 : color);
+    }
+
+    /**
+     * process <code>SGR 48</code> corresponding to <code>extended set background color</code>
+     * with a palette of 255 colors.
+     * @param paletteIndex the background color in the palette
+     * @throws IOException if an error occurs
+     */
+    protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
+    }
+
+    /**
+     * process <code>SGR 48</code> corresponding to <code>extended set background color</code>
+     * with a 24 bits RGB definition of the color.
+     * @param r red
+     * @param g green
+     * @param b blue
+     * @throws IOException if an error occurs
+     */
+    protected void processSetBackgroundColorExt(int r, int g, int b) throws IOException {
+        processSetBackgroundColorExt(Colors.roundRgbColor(r, g, b, 16));
+    }
+
+    /**
+     * process <code>SGR 39</code> corresponding to <code>Default text color (foreground)</code>
+     * @throws IOException if an error occurs
+     */
+    protected void processDefaultTextColor() throws IOException {
+    }
+
+    /**
+     * process <code>SGR 49</code> corresponding to <code>Default background color</code>
+     * @throws IOException if an error occurs
+     */
+    protected void processDefaultBackgroundColor() throws IOException {
+    }
+
+    /**
+     * process <code>SGR 0</code> corresponding to <code>Reset / Normal</code>
+     * @throws IOException if an error occurs
+     */
+    protected void processAttributeRest() throws IOException {
+    }
+
+    /**
+     * process <code>CSI n ; m H</code> corresponding to <code>CUP \u2013 Cursor Position</code> or
+     * <code>CSI n ; m f</code> corresponding to <code>HVP \u2013 Horizontal and Vertical Position</code>
+     * @param row the row
+     * @param col the column
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorTo(int row, int col) throws IOException {
+    }
+
+    /**
+     * process <code>CSI n G</code> corresponding to <code>CHA \u2013 Cursor Horizontal Absolute</code>
+     * @param x the column
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorToColumn(int x) throws IOException {
+    }
+
+    /**
+     * process <code>CSI n F</code> corresponding to <code>CPL \u2013 Cursor Previous Line</code>
+     * @param count line count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorUpLine(int count) throws IOException {
+    }
+
+    /**
+     * process <code>CSI n E</code> corresponding to <code>CNL \u2013 Cursor Next Line</code>
+     * @param count line count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorDownLine(int count) throws IOException {
+        // Poor mans impl..
+        for (int i = 0; i < count; i++) {
+            out.write('\n');
+        }
+    }
+
+    /**
+     * process <code>CSI n D</code> corresponding to <code>CUB \u2013 Cursor Back</code>
+     * @param count the count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorLeft(int count) throws IOException {
+    }
+
+    /**
+     * process <code>CSI n C</code> corresponding to <code>CUF \u2013 Cursor Forward</code>
+     * @param count the count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorRight(int count) throws IOException {
+        // Poor mans impl..
+        for (int i = 0; i < count; i++) {
+            out.write(' ');
+        }
+    }
+
+    /**
+     * process <code>CSI n B</code> corresponding to <code>CUD \u2013 Cursor Down</code>
+     * @param count the count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorDown(int count) throws IOException {
+    }
+
+    /**
+     * process <code>CSI n A</code> corresponding to <code>CUU \u2013 Cursor Up</code>
+     * @param count the count
+     * @throws IOException if an error occurs
+     */
+    protected void processCursorUp(int count) throws IOException {
+    }
+
+    protected void processUnknownExtension(ArrayList<Object> options, int command) {
+    }
+
+    /**
+     * process <code>OSC 0;text BEL</code> corresponding to <code>Change Window and Icon label</code>
+     * @param label the label
+     */
+    protected void processChangeIconNameAndWindowTitle(String label) {
+        processChangeIconName(label);
+        processChangeWindowTitle(label);
+    }
+
+    /**
+     * process <code>OSC 1;text BEL</code> corresponding to <code>Change Icon label</code>
+     * @param name the icon name
+     */
+    protected void processChangeIconName(String name) {
+    }
+
+    /**
+     * process <code>OSC 2;text BEL</code> corresponding to <code>Change Window title</code>
+     * @param title the title
+     */
+    protected void processChangeWindowTitle(String title) {
+    }
+
+    /**
+     * Process unknown <code>OSC</code> command.
+     * @param command the command
+     * @param param the param
+     */
+    protected void processUnknownOperatingSystemCommand(int command, String param) {
+    }
+
+    /**
+     * Process character set sequence.
+     * @param options
+     * @return true if the charcter set select command was processed.
+     */
+    private boolean processCharsetSelect(ArrayList<Object> options) throws IOException {
+        int set = optionInt(options, 0);
+        char seq = (Character) options.get(1);
+        processCharsetSelect(set, seq);
+        return true;
+    }
+
+    protected void processCharsetSelect(int set, char seq) {
+    }
+
+    private int optionInt(ArrayList<Object> options, int index) {
+        if (options.size() <= index)
+            throw new IllegalArgumentException();
+        Object value = options.get(index);
+        if (value == null)
+            throw new IllegalArgumentException();
+        if (!value.getClass().equals(Integer.class))
+            throw new IllegalArgumentException();
+        return (Integer) value;
+    }
+
+    private int optionInt(ArrayList<Object> options, int index, int defaultValue) {
+        if (options.size() > index) {
+            Object value = options.get(index);
+            if (value == null) {
+                return defaultValue;
+            }
+            return (Integer) value;
+        }
+        return defaultValue;
+    }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        // TODO: Optimize this
+        for (int i = 0; i < len; i++) {
+            write(cbuf[off + i]);
+        }
+    }
+
+    @Override
+    public void write(String str, int off, int len) throws IOException {
+        // TODO: Optimize this
+        for (int i = 0; i < len; i++) {
+            write(str.charAt(off + i));
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        write(RESET_CODE);
+        flush();
+        super.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,350 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+
+import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR;
+import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP;
+import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR;
+import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR_EXP;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_BACKGROUND;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_BLINK;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_BOLD;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_CONCEAL;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_CROSSED_OUT;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_FAINT;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_INVERSE;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_ITALIC;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_UNDERLINE;
+import static jdk.internal.org.jline.utils.AttributedStyle.F_HIDDEN;
+import static jdk.internal.org.jline.utils.AttributedStyle.MASK;
+import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTERNATE_CHARSET;
+
+public abstract class AttributedCharSequence implements CharSequence {
+
+    // 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 String toAnsi() {
+        return toAnsi(null);
+    }
+
+    public String toAnsi(Terminal terminal) {
+        if (terminal != null && Terminal.TYPE_DUMB.equals(terminal.getType())) {
+            return toString();
+        }
+        int colors = 256;
+        boolean force256colors = false;
+        String alternateIn = null, alternateOut = null;
+        if (terminal != null) {
+            Integer max_colors = terminal.getNumericCapability(Capability.max_colors);
+            if (max_colors != null) {
+                colors = max_colors;
+            }
+            force256colors = AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR.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));
+            }
+        }
+        return toAnsi(colors, force256colors, alternateIn, alternateOut);
+    }
+
+    public String toAnsi(int colors, boolean force256colors) {
+        return toAnsi(colors, force256colors, null, null);
+    }
+
+    public String toAnsi(int colors, boolean force256colors, String altIn, String altOut) {
+        StringBuilder sb = new StringBuilder();
+        int style = 0;
+        int foreground = -1;
+        int background = -1;
+        boolean alt = false;
+        for (int i = 0; i < length(); i++) {
+            char c = charAt(i);
+            if (altIn != null && altOut != null) {
+                char pc = c;
+                switch (c) {
+                    case '\u2518': c = 'j'; break;
+                    case '\u2510': c = 'k'; break;
+                    case '\u250C': c = 'l'; break;
+                    case '\u2514': c = 'm'; break;
+                    case '\u253C': c = 'n'; break;
+                    case '\u2500': c = 'q'; break;
+                    case '\u251C': c = 't'; break;
+                    case '\u2524': c = 'u'; break;
+                    case '\u2534': c = 'v'; break;
+                    case '\u252C': c = 'w'; break;
+                    case '\u2502': c = 'x'; break;
+                }
+                boolean oldalt = alt;
+                alt = c != pc;
+                if (oldalt ^ alt) {
+                    sb.append(alt ? altIn : altOut);
+                }
+            }
+            int  s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles
+            if (style != s) {
+                int  d = (style ^ s) & MASK;
+                int fg = (s & F_FOREGROUND) != 0 ? (s & FG_COLOR) >>> FG_COLOR_EXP : -1;
+                int bg = (s & F_BACKGROUND) != 0 ? (s & BG_COLOR) >>> BG_COLOR_EXP : -1;
+                if (s == 0) {
+                    sb.append("\033[0m");
+                    foreground = background = -1;
+                } else {
+                    sb.append("\033[");
+                    boolean first = true;
+                    if ((d & F_ITALIC) != 0) {
+                        first = attr(sb, (s & F_ITALIC) != 0 ? "3" : "23", first);
+                    }
+                    if ((d & F_UNDERLINE) != 0) {
+                        first = attr(sb, (s & F_UNDERLINE) != 0 ? "4" : "24", first);
+                    }
+                    if ((d & F_BLINK) != 0) {
+                        first = attr(sb, (s & F_BLINK) != 0 ? "5" : "25", first);
+                    }
+                    if ((d & F_INVERSE) != 0) {
+                        first = attr(sb, (s & F_INVERSE) != 0 ? "7" : "27", first);
+                    }
+                    if ((d & F_CONCEAL) != 0) {
+                        first = attr(sb, (s & F_CONCEAL) != 0 ? "8" : "28", first);
+                    }
+                    if ((d & F_CROSSED_OUT) != 0) {
+                        first = attr(sb, (s & F_CROSSED_OUT) != 0 ? "9" : "29", first);
+                    }
+                    if (foreground != fg) {
+                        if (fg >= 0) {
+                            int rounded = Colors.roundColor(fg, colors);
+                            if (rounded < 8 && !force256colors) {
+                                first = attr(sb, "3" + Integer.toString(rounded), first);
+                                // small hack to force setting bold again after a foreground color change
+                                d |= (s & F_BOLD);
+                            } else if (rounded < 16 && !force256colors) {
+                                first = attr(sb, "9" + Integer.toString(rounded - 8), first);
+                                // small hack to force setting bold again after a foreground color change
+                                d |= (s & F_BOLD);
+                            } else {
+                                first = attr(sb, "38;5;" + Integer.toString(rounded), first);
+                            }
+                        } else {
+                            first = attr(sb, "39", first);
+                        }
+                        foreground = fg;
+                    }
+                    if (background != bg) {
+                        if (bg >= 0) {
+                            int rounded = Colors.roundColor(bg, colors);
+                            if (rounded < 8 && !force256colors) {
+                                first = attr(sb, "4" + Integer.toString(rounded), first);
+                            } else if (rounded < 16 && !force256colors) {
+                                first = attr(sb, "10" + Integer.toString(rounded - 8), first);
+                            } else {
+                                first = attr(sb, "48;5;" + Integer.toString(rounded), first);
+                            }
+                        } else {
+                            first = attr(sb, "49", first);
+                        }
+                        background = bg;
+                    }
+                    if ((d & (F_BOLD | F_FAINT)) != 0) {
+                        if (    (d & F_BOLD)  != 0 && (s & F_BOLD)  == 0
+                                || (d & F_FAINT) != 0 && (s & F_FAINT) == 0) {
+                            first = attr(sb, "22", first);
+                        }
+                        if ((d & F_BOLD) != 0 && (s & F_BOLD) != 0) {
+                            first = attr(sb, "1", first);
+                        }
+                        if ((d & F_FAINT) != 0 && (s & F_FAINT) != 0) {
+                            first = attr(sb, "2", first);
+                        }
+                    }
+                    sb.append("m");
+                }
+                style = s;
+            }
+            sb.append(c);
+        }
+        if (alt) {
+            sb.append(altOut);
+        }
+        if (style != 0) {
+            sb.append("\033[0m");
+        }
+        return sb.toString();
+    }
+
+    @Deprecated
+    public static int rgbColor(int col) {
+        return Colors.rgbColor(col);
+    }
+
+    @Deprecated
+    public static int roundColor(int col, int max) {
+        return Colors.roundColor(col, max);
+    }
+
+    @Deprecated
+    public static int roundRgbColor(int r, int g, int b, int max) {
+        return Colors.roundRgbColor(r, g, b, max);
+    }
+
+    private static boolean attr(StringBuilder sb, String s, boolean first) {
+        if (!first) {
+            sb.append(";");
+        }
+        sb.append(s);
+        return false;
+    }
+
+    public abstract AttributedStyle styleAt(int index);
+
+    int styleCodeAt(int index) {
+        return styleAt(index).getStyle();
+    }
+
+    public boolean isHidden(int index) {
+        return (styleCodeAt(index) & F_HIDDEN) != 0;
+    }
+
+    public int runStart(int index) {
+        AttributedStyle style = styleAt(index);
+        while (index > 0 && styleAt(index - 1).equals(style)) {
+            index--;
+        }
+        return index;
+    }
+
+    public int runLimit(int index) {
+        AttributedStyle style = styleAt(index);
+        while (index < length() - 1 && styleAt(index + 1).equals(style)) {
+            index++;
+        }
+        return index + 1;
+    }
+
+    @Override
+    public abstract AttributedString subSequence(int start, int end);
+
+    public AttributedString substring(int start, int end) {
+        return subSequence(start, end);
+    }
+
+    protected abstract char[] buffer();
+
+    protected abstract int offset();
+
+    @Override
+    public char charAt(int index) {
+        return buffer()[offset() + index];
+    }
+
+    public int codePointAt(int index) {
+        return Character.codePointAt(buffer(), index + offset());
+    }
+
+    public boolean contains(char c) {
+        for (int i = 0; i < length(); i++) {
+            if (charAt(i) == c) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int codePointBefore(int index) {
+        return Character.codePointBefore(buffer(), index + offset());
+    }
+
+    public int codePointCount(int index, int length) {
+        return Character.codePointCount(buffer(), index + offset(), length);
+    }
+
+    public int columnLength() {
+        int cols = 0;
+        int len = length();
+        for (int cur = 0; cur < len; ) {
+            int cp = codePointAt(cur);
+            if (!isHidden(cur))
+                cols += WCWidth.wcwidth(cp);
+            cur += Character.charCount(cp);
+        }
+        return cols;
+    }
+
+    public AttributedString columnSubSequence(int start, int stop) {
+        int begin = 0;
+        int col = 0;
+        while (begin < this.length()) {
+            int cp = codePointAt(begin);
+            int w = isHidden(begin) ? 0 : WCWidth.wcwidth(cp);
+            if (col + w > start) {
+                break;
+            }
+            begin++;
+            col += w;
+        }
+        int end = begin;
+        while (end < this.length()) {
+            int cp = codePointAt(end);
+            if (cp == '\n')
+                break;
+            int w = isHidden(end) ? 0 : WCWidth.wcwidth(cp);
+            if (col + w > stop) {
+                break;
+            }
+            end++;
+            col += w;
+        }
+        return subSequence(begin, end);
+    }
+
+    public List<AttributedString> columnSplitLength(int columns) {
+        return columnSplitLength(columns, false, true);
+    }
+
+    public List<AttributedString> columnSplitLength(int columns, boolean includeNewlines, boolean delayLineWrap) {
+        List<AttributedString> strings = new ArrayList<>();
+        int cur = 0;
+        int beg = cur;
+        int col = 0;
+        while (cur < length()) {
+            int cp = codePointAt(cur);
+            int w = isHidden(cur) ? 0 : WCWidth.wcwidth(cp);
+            if (cp == '\n') {
+                strings.add(subSequence(beg, includeNewlines ? cur+1 : cur));
+                beg = cur + 1;
+                col = 0;
+            } else if ((col += w) > columns) {
+                strings.add(subSequence(beg, cur));
+                beg = cur;
+                col = w;
+            }
+            cur += Character.charCount(cp);
+        }
+        strings.add(subSequence(beg, cur));
+        return strings;
+    }
+
+    @Override
+    public String toString() {
+        return new String(buffer(), offset(), length());
+    }
+
+    public AttributedString toAttributedString() {
+        return substring(0, length());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,220 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.security.InvalidParameterException;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Attributed string.
+ * Instances of this class are immutables.
+ * Substrings are created without any memory copy.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class AttributedString extends AttributedCharSequence {
+
+    final char[] buffer;
+    final int[] style;
+    final int start;
+    final int end;
+    public static final AttributedString EMPTY = new AttributedString("");
+    public static final AttributedString NEWLINE = new AttributedString("\n");
+
+    public AttributedString(CharSequence str) {
+        this(str, 0, str.length(), null);
+    }
+
+    public AttributedString(CharSequence str, int start, int end) {
+        this(str, start, end, null);
+    }
+
+    public AttributedString(CharSequence str, AttributedStyle s) {
+        this(str, 0, str.length(), s);
+    }
+
+    public AttributedString(CharSequence str, int start, int end, AttributedStyle s) {
+        if (end < start) {
+            throw new InvalidParameterException();
+        }
+        if (str instanceof AttributedString) {
+            AttributedString as = (AttributedString) str;
+            this.buffer = as.buffer;
+            if (s != null) {
+                this.style = as.style.clone();
+                for (int i = 0; i < style.length; i++) {
+                    this.style[i] = (this.style[i] & ~s.getMask()) | s.getStyle();
+                }
+            } else {
+                this.style = as.style;
+            }
+            this.start = as.start + start;
+            this.end = as.start + end;
+        } else if (str instanceof AttributedStringBuilder) {
+            AttributedStringBuilder asb = (AttributedStringBuilder) str;
+            AttributedString as = asb.subSequence(start, end);
+            this.buffer = as.buffer;
+            this.style = as.style;
+            if (s != null) {
+                for (int i = 0; i < style.length; i++) {
+                    this.style[i] = (this.style[i] & ~s.getMask()) | s.getStyle();
+                }
+            }
+            this.start = as.start;
+            this.end = as.end;
+        } else {
+            int l = end - start;
+            buffer = new char[l];
+            for (int i = 0; i < l; i++) {
+                buffer[i] = str.charAt(start + i);
+            }
+            style = new int[l];
+            if (s != null) {
+                Arrays.fill(style, s.getStyle());
+            }
+            this.start = 0;
+            this.end = l;
+        }
+    }
+
+    AttributedString(char[] buffer, int[] style, int start, int end) {
+        this.buffer = buffer;
+        this.style = style;
+        this.start = start;
+        this.end = end;
+    }
+
+    public static AttributedString fromAnsi(String ansi) {
+        return fromAnsi(ansi, 0);
+    }
+
+    public static AttributedString fromAnsi(String ansi, int tabs) {
+        if (ansi == null) {
+            return null;
+        }
+        return new AttributedStringBuilder(ansi.length())
+                .tabs(tabs)
+                .ansiAppend(ansi)
+                .toAttributedString();
+    }
+
+    public static String stripAnsi(String ansi) {
+        if (ansi == null) {
+            return null;
+        }
+        return new AttributedStringBuilder(ansi.length())
+                .ansiAppend(ansi)
+                .toString();
+    }
+
+    @Override
+    protected char[] buffer() {
+        return buffer;
+    }
+
+    @Override
+    protected int offset() {
+        return start;
+    }
+
+    @Override
+    public int length() {
+        return end - start;
+    }
+
+    @Override
+    public AttributedStyle styleAt(int index) {
+        return new AttributedStyle(style[start + index], style[start + index]);
+    }
+
+    @Override
+    int styleCodeAt(int index) {
+        return style[start + index];
+    }
+
+    @Override
+    public AttributedString subSequence(int start, int end) {
+        return new AttributedString(this, start, end);
+    }
+
+    public AttributedString styleMatches(Pattern pattern, AttributedStyle style) {
+        Matcher matcher = pattern.matcher(this);
+        boolean result = matcher.find();
+        if (result) {
+            int[] newstyle = this.style.clone();
+            do {
+                for (int i = matcher.start(); i < matcher.end(); i++) {
+                    newstyle[this.start + i] = (newstyle[this.start + i] & ~style.getMask()) | style.getStyle();
+                }
+                result = matcher.find();
+            } while (result);
+            return new AttributedString(buffer, newstyle, start , end);
+        }
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        AttributedString that = (AttributedString) o;
+        return end - start == that.end - that.start
+                && arrEq(buffer, that.buffer, start, that.start, end - start)
+                && arrEq(style, that.style, start, that.start, end - start);
+    }
+
+    private boolean arrEq(char[] a1, char[] a2, int s1, int s2, int l) {
+        for (int i = 0; i < l; i++) {
+            if (a1[s1+i] != a2[s2+i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+    private boolean arrEq(int[] a1, int[] a2, int s1, int s2, int l) {
+        for (int i = 0; i < l; i++) {
+            if (a1[s1+i] != a2[s2+i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Arrays.hashCode(buffer);
+        result = 31 * result + Arrays.hashCode(style);
+        result = 31 * result + start;
+        result = 31 * result + end;
+        return result;
+    }
+
+    public static AttributedString join(AttributedString delimiter, AttributedString... elements) {
+        Objects.requireNonNull(delimiter);
+        Objects.requireNonNull(elements);
+        return join(delimiter, Arrays.asList(elements));
+    }
+
+    public static AttributedString join(AttributedString delimiter, Iterable<AttributedString> elements) {
+        Objects.requireNonNull(elements);
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        int i = 0;
+        for (AttributedString str : elements) {
+            if (i++ > 0 && delimiter != null) {
+                sb.append(delimiter);
+            }
+            sb.append(str);
+        }
+        return sb.toAttributedString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,396 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Attributed string builder
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class AttributedStringBuilder extends AttributedCharSequence implements Appendable {
+
+    private char[] buffer;
+    private int[] style;
+    private int length;
+    private int tabs = 0;
+    private int lastLineLength = 0;
+    private AttributedStyle current = AttributedStyle.DEFAULT;
+
+    public static AttributedString append(CharSequence... strings) {
+        AttributedStringBuilder sb = new AttributedStringBuilder();
+        for (CharSequence s : strings) {
+            sb.append(s);
+        }
+        return sb.toAttributedString();
+    }
+
+    public AttributedStringBuilder() {
+        this(64);
+    }
+
+    public AttributedStringBuilder(int capacity) {
+        buffer = new char[capacity];
+        style = new int[capacity];
+        length = 0;
+    }
+
+    @Override
+    public int length() {
+        return length;
+    }
+
+    @Override
+    public char charAt(int index) {
+        return buffer[index];
+    }
+
+    @Override
+    public AttributedStyle styleAt(int index) {
+        return new AttributedStyle(style[index], style[index]);
+    }
+
+    @Override
+    int styleCodeAt(int index) {
+        return style[index];
+    }
+
+    @Override
+    protected char[] buffer() {
+        return buffer;
+    }
+
+    @Override
+    protected int offset() {
+        return 0;
+    }
+
+    @Override
+    public AttributedString subSequence(int start, int end) {
+        return new AttributedString(
+                Arrays.copyOfRange(buffer, start, end),
+                Arrays.copyOfRange(style, start, end),
+                0,
+                end - start);
+    }
+
+    @Override
+    public AttributedStringBuilder append(CharSequence csq) {
+        return append(new AttributedString(csq, current));
+    }
+
+    @Override
+    public AttributedStringBuilder append(CharSequence csq, int start, int end) {
+        return append(csq.subSequence(start, end));
+    }
+
+    @Override
+    public AttributedStringBuilder append(char c) {
+        return append(Character.toString(c));
+    }
+
+    public AttributedStringBuilder append(CharSequence csq, AttributedStyle style) {
+        return append(new AttributedString(csq, style));
+    }
+
+    public AttributedStringBuilder style(AttributedStyle style) {
+        current = style;
+        return this;
+    }
+
+    public AttributedStringBuilder style(Function<AttributedStyle,AttributedStyle> style) {
+        current = style.apply(current);
+        return this;
+    }
+
+    public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, CharSequence cs) {
+        return styled(style, sb -> sb.append(cs));
+    }
+
+    public AttributedStringBuilder styled(AttributedStyle style, CharSequence cs) {
+        return styled(s -> style, sb -> sb.append(cs));
+    }
+
+    public AttributedStringBuilder styled(Function<AttributedStyle,AttributedStyle> style, Consumer<AttributedStringBuilder> consumer) {
+        AttributedStyle prev = current;
+        current = style.apply(prev);
+        consumer.accept(this);
+        current = prev;
+        return this;
+    }
+
+    public AttributedStyle style() {
+        return current;
+    }
+
+    public AttributedStringBuilder append(AttributedString str) {
+        return append((AttributedCharSequence) str, 0, str.length());
+    }
+
+    public AttributedStringBuilder append(AttributedString str, int start, int end) {
+        return append((AttributedCharSequence) str, start, end);
+    }
+
+    public AttributedStringBuilder append(AttributedCharSequence str) {
+        return append(str, 0, str.length());
+    }
+
+    public AttributedStringBuilder append(AttributedCharSequence str, int start, int end) {
+        ensureCapacity(length + end - start);
+        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') {
+                insertTab(new AttributedStyle(s, 0));
+            } else {
+                ensureCapacity(length + 1);
+                buffer[length] = c;
+                style[length] = s;
+                if (c == '\n') {
+                    lastLineLength = 0;
+                } else {
+                    lastLineLength++;
+                }
+                length++;
+            }
+        }
+        return this;
+    }
+
+    protected void ensureCapacity(int nl) {
+        if (nl > buffer.length) {
+            int s = Math.max(buffer.length, 1);
+            while (s <= nl) {
+                s *= 2;
+            }
+            buffer = Arrays.copyOf(buffer, s);
+            style = Arrays.copyOf(style, s);
+        }
+    }
+
+    public void appendAnsi(String ansi) {
+        ansiAppend(ansi);
+    }
+
+    public AttributedStringBuilder ansiAppend(String ansi) {
+        int ansiStart = 0;
+        int ansiState = 0;
+        ensureCapacity(length + ansi.length());
+        for (int i = 0; i < ansi.length(); i++) {
+            char c = ansi.charAt(i);
+            if (ansiState == 0 && c == 27) {
+                ansiState++;
+            } else if (ansiState == 1 && c == '[') {
+                ansiState++;
+                ansiStart = i + 1;
+            } else if (ansiState == 2) {
+                if (c == 'm') {
+                    String[] params = ansi.substring(ansiStart, i).split(";");
+                    int j = 0;
+                    while (j < params.length) {
+                        int ansiParam = params[j].isEmpty() ? 0 : Integer.parseInt(params[j]);
+                        switch (ansiParam) {
+                            case 0:
+                                current = AttributedStyle.DEFAULT;
+                                break;
+                            case 1:
+                                current = current.bold();
+                                break;
+                            case 2:
+                                current = current.faint();
+                                break;
+                            case 3:
+                                current = current.italic();
+                                break;
+                            case 4:
+                                current = current.underline();
+                                break;
+                            case 5:
+                                current = current.blink();
+                                break;
+                            case 7:
+                                current = current.inverse();
+                                break;
+                            case 8:
+                                current = current.conceal();
+                                break;
+                            case 9:
+                                current = current.crossedOut();
+                                break;
+                            case 22:
+                                current = current.boldOff().faintOff();
+                                break;
+                            case 23:
+                                current = current.italicOff();
+                                break;
+                            case 24:
+                                current = current.underlineOff();
+                                break;
+                            case 25:
+                                current = current.blinkOff();
+                                break;
+                            case 27:
+                                current = current.inverseOff();
+                                break;
+                            case 28:
+                                current = current.concealOff();
+                                break;
+                            case 29:
+                                current = current.crossedOutOff();
+                                break;
+                            case 30:
+                            case 31:
+                            case 32:
+                            case 33:
+                            case 34:
+                            case 35:
+                            case 36:
+                            case 37:
+                                current = current.foreground(ansiParam - 30);
+                                break;
+                            case 39:
+                                current = current.foregroundOff();
+                                break;
+                            case 40:
+                            case 41:
+                            case 42:
+                            case 43:
+                            case 44:
+                            case 45:
+                            case 46:
+                            case 47:
+                                current = current.background(ansiParam - 40);
+                                break;
+                            case 49:
+                                current = current.backgroundOff();
+                                break;
+                            case 38:
+                            case 48:
+                                if (j + 1 < params.length) {
+                                    int ansiParam2 = Integer.parseInt(params[++j]);
+                                    if (ansiParam2 == 2) {
+                                        if (j + 3 < params.length) {
+                                            int r = Integer.parseInt(params[++j]);
+                                            int g = Integer.parseInt(params[++j]);
+                                            int b = Integer.parseInt(params[++j]);
+                                            // convert to 256 colors
+                                            int col = 16 + (r >> 3) * 36 + (g >> 3) * 6 + (b >> 3);
+                                            if (ansiParam == 38) {
+                                                current = current.foreground(col);
+                                            } else {
+                                                current = current.background(col);
+                                            }
+                                        }
+                                    } else if (ansiParam2 == 5) {
+                                        if (j + 1 < params.length) {
+                                            int col = Integer.parseInt(params[++j]);
+                                            if (ansiParam == 38) {
+                                                current = current.foreground(col);
+                                            } else {
+                                                current = current.background(col);
+                                            }
+                                        }
+                                    }
+                                }
+                                break;
+                            case 90:
+                            case 91:
+                            case 92:
+                            case 93:
+                            case 94:
+                            case 95:
+                            case 96:
+                            case 97:
+                                current = current.foreground(ansiParam - 90 + 8);
+                                break;
+                            case 100:
+                            case 101:
+                            case 102:
+                            case 103:
+                            case 104:
+                            case 105:
+                            case 106:
+                            case 107:
+                                current = current.background(ansiParam - 100 + 8);
+                                break;
+                        }
+                        j++;
+                    }
+                    ansiState = 0;
+                } else if (!(c >= '0' && c <= '9' || c == ';')) {
+                    // This is not a SGR code, so ignore
+                    ansiState = 0;
+                }
+            } else if (c == '\t' && tabs > 0) {
+                insertTab(current);
+            } else {
+                ensureCapacity(length + 1);
+                buffer[length] = c;
+                style[length] = this.current.getStyle();
+                if (c == '\n') {
+                    lastLineLength = 0;
+                } else {
+                    lastLineLength++;
+                }
+                length++;
+            }
+        }
+        return this;
+    }
+
+    protected void insertTab(AttributedStyle s) {
+        int nb = tabs - lastLineLength % tabs;
+        ensureCapacity(length + nb);
+        for (int i = 0; i < nb; i++) {
+            buffer[length] = ' ';
+            style[length] = s.getStyle();
+            length++;
+        }
+        lastLineLength += nb;
+    }
+
+    public void setLength(int l) {
+        length = l;
+    }
+
+    /**
+     * Set the number of spaces a tab is expanded to. Tab size cannot be changed
+     * after text has been added to prevent inconsistent indentation.
+     *
+     * If tab size is set to 0, tabs are not expanded (the default).
+     * @param tabsize Spaces per tab or 0 for no tab expansion. Must be non-negative
+     * @return this
+     */
+    public AttributedStringBuilder tabs(int tabsize) {
+        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;
+        return this;
+    }
+
+    public AttributedStringBuilder styleMatches(Pattern pattern, AttributedStyle s) {
+        Matcher matcher = pattern.matcher(this);
+        while (matcher.find()) {
+            for (int i = matcher.start(); i < matcher.end(); i++) {
+                style[i] = (style[i] & ~s.getMask()) | s.getStyle();
+            }
+        }
+        return this;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+/**
+ * Text styling.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class AttributedStyle {
+
+    public static final int BLACK =     0;
+    public static final int RED =       1;
+    public static final int GREEN =     2;
+    public static final int YELLOW =    3;
+    public static final int BLUE =      4;
+    public static final int MAGENTA =   5;
+    public static final int CYAN =      6;
+    public static final int WHITE =     7;
+
+    public static final int BRIGHT =    8;
+
+    static final int F_BOLD         = 0x00000001;
+    static final int F_FAINT        = 0x00000002;
+    static final int F_ITALIC       = 0x00000004;
+    static final int F_UNDERLINE    = 0x00000008;
+    static final int F_BLINK        = 0x00000010;
+    static final int F_INVERSE      = 0x00000020;
+    static final int F_CONCEAL      = 0x00000040;
+    static final int F_CROSSED_OUT  = 0x00000080;
+    static final int F_FOREGROUND   = 0x00000100;
+    static final int F_BACKGROUND   = 0x00000200;
+    static final int F_HIDDEN       = 0x00000400;
+
+    static final int MASK           = 0x000007FF;
+
+    static final int FG_COLOR_EXP    = 16;
+    static final int BG_COLOR_EXP    = 24;
+    static final int FG_COLOR        = 0xFF << FG_COLOR_EXP;
+    static final int BG_COLOR        = 0xFF << BG_COLOR_EXP;
+
+    public static final AttributedStyle DEFAULT = new AttributedStyle();
+    public static final AttributedStyle BOLD = DEFAULT.bold();
+    public static final AttributedStyle BOLD_OFF = DEFAULT.boldOff();
+    public static final AttributedStyle INVERSE = DEFAULT.inverse();
+    public static final AttributedStyle INVERSE_OFF = DEFAULT.inverseOff();
+    public static final AttributedStyle HIDDEN = DEFAULT.hidden();
+    public static final AttributedStyle HIDDEN_OFF = DEFAULT.hiddenOff();
+
+    final int style;
+    final int mask;
+
+    public AttributedStyle() {
+        this(0, 0);
+    }
+
+    public AttributedStyle(AttributedStyle s) {
+        this(s.style, s.mask);
+    }
+
+    public AttributedStyle(int style, int mask) {
+        this.style = style;
+        this.mask = mask & MASK | ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0)
+                                | ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0);
+    }
+
+    public AttributedStyle bold() {
+        return new AttributedStyle(style | F_BOLD, mask | F_BOLD);
+    }
+
+    public AttributedStyle boldOff() {
+        return new AttributedStyle(style & ~F_BOLD, mask | F_BOLD);
+    }
+
+    public AttributedStyle boldDefault() {
+        return new AttributedStyle(style & ~F_BOLD, mask & ~F_BOLD);
+    }
+
+    public AttributedStyle faint() {
+        return new AttributedStyle(style | F_FAINT, mask | F_FAINT);
+    }
+
+    public AttributedStyle faintOff() {
+        return new AttributedStyle(style & ~F_FAINT, mask | F_FAINT);
+    }
+
+    public AttributedStyle faintDefault() {
+        return new AttributedStyle(style & ~F_FAINT, mask & ~F_FAINT);
+    }
+
+    public AttributedStyle italic() {
+        return new AttributedStyle(style | F_ITALIC, mask | F_ITALIC);
+    }
+
+    public AttributedStyle italicOff() {
+        return new AttributedStyle(style & ~F_ITALIC, mask | F_ITALIC);
+    }
+
+    public AttributedStyle italicDefault() {
+        return new AttributedStyle(style & ~F_ITALIC, mask & ~F_ITALIC);
+    }
+
+    public AttributedStyle underline() {
+        return new AttributedStyle(style | F_UNDERLINE, mask | F_UNDERLINE);
+    }
+
+    public AttributedStyle underlineOff() {
+        return new AttributedStyle(style & ~F_UNDERLINE, mask | F_UNDERLINE);
+    }
+
+    public AttributedStyle underlineDefault() {
+        return new AttributedStyle(style & ~F_UNDERLINE, mask & ~F_UNDERLINE);
+    }
+
+    public AttributedStyle blink() {
+        return new AttributedStyle(style | F_BLINK, mask | F_BLINK);
+    }
+
+    public AttributedStyle blinkOff() {
+        return new AttributedStyle(style & ~F_BLINK, mask | F_BLINK);
+    }
+
+    public AttributedStyle blinkDefault() {
+        return new AttributedStyle(style & ~F_BLINK, mask & ~F_BLINK);
+    }
+
+    public AttributedStyle inverse() {
+        return new AttributedStyle(style | F_INVERSE, mask | F_INVERSE);
+    }
+
+    public AttributedStyle inverseNeg() {
+        int s = (style & F_INVERSE) != 0 ? style & ~F_INVERSE : style | F_INVERSE;
+        return new AttributedStyle(s, mask | F_INVERSE);
+    }
+
+    public AttributedStyle inverseOff() {
+        return new AttributedStyle(style & ~F_INVERSE, mask | F_INVERSE);
+    }
+
+    public AttributedStyle inverseDefault() {
+        return new AttributedStyle(style & ~F_INVERSE, mask & ~F_INVERSE);
+    }
+
+    public AttributedStyle conceal() {
+        return new AttributedStyle(style | F_CONCEAL, mask | F_CONCEAL);
+    }
+
+    public AttributedStyle concealOff() {
+        return new AttributedStyle(style & ~F_CONCEAL, mask | F_CONCEAL);
+    }
+
+    public AttributedStyle concealDefault() {
+        return new AttributedStyle(style & ~F_CONCEAL, mask & ~F_CONCEAL);
+    }
+
+    public AttributedStyle crossedOut() {
+        return new AttributedStyle(style | F_CROSSED_OUT, mask | F_CROSSED_OUT);
+    }
+
+    public AttributedStyle crossedOutOff() {
+        return new AttributedStyle(style & ~F_CROSSED_OUT, mask | F_CROSSED_OUT);
+    }
+
+    public AttributedStyle crossedOutDefault() {
+        return new AttributedStyle(style & ~F_CROSSED_OUT, mask & ~F_CROSSED_OUT);
+    }
+
+    public AttributedStyle foreground(int color) {
+        return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND | ((color << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND);
+    }
+
+    public AttributedStyle foregroundOff() {
+        return new AttributedStyle(style & ~FG_COLOR & ~F_FOREGROUND, mask | F_FOREGROUND);
+    }
+
+    public AttributedStyle foregroundDefault() {
+        return new AttributedStyle(style & ~FG_COLOR & ~F_FOREGROUND, mask & ~(F_FOREGROUND | FG_COLOR));
+    }
+
+    public AttributedStyle background(int color) {
+        return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND | ((color << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND);
+    }
+
+    public AttributedStyle backgroundOff() {
+        return new AttributedStyle(style & ~BG_COLOR & ~F_BACKGROUND, mask | F_BACKGROUND);
+    }
+
+    public AttributedStyle backgroundDefault() {
+        return new AttributedStyle(style & ~BG_COLOR & ~F_BACKGROUND, mask & ~(F_BACKGROUND | BG_COLOR));
+    }
+
+    /**
+     * The hidden flag can be used to embed custom escape sequences.
+     * The characters are considered being 0-column long and will be printed as-is.
+     * The user is responsible for ensuring that those sequences do not move the cursor.
+     *
+     * @return the new style
+     */
+    public AttributedStyle hidden() {
+        return new AttributedStyle(style | F_HIDDEN, mask | F_HIDDEN);
+    }
+
+    public AttributedStyle hiddenOff() {
+        return new AttributedStyle(style & ~F_HIDDEN, mask | F_HIDDEN);
+    }
+
+    public AttributedStyle hiddenDefault() {
+        return new AttributedStyle(style & ~F_HIDDEN, mask & ~F_HIDDEN);
+    }
+
+    public int getStyle() {
+        return style;
+    }
+
+    public int getMask() {
+        return mask;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        AttributedStyle that = (AttributedStyle) o;
+        if (style != that.style) return false;
+        return mask == that.mask;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = style;
+        result = 31 * result + mask;
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ClosedException.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+
+public class ClosedException extends IOException {
+
+    private static final long serialVersionUID = 3085420657077696L;
+
+    public ClosedException() {
+    }
+
+    public ClosedException(String message) {
+        super(message);
+    }
+
+    public ClosedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ClosedException(Throwable cause) {
+        super(cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.BufferedReader;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_COLOR_DISTANCE;
+
+public class Colors {
+
+    /**
+     * Default 256 colors palette
+     */
+    public static final int[] DEFAULT_COLORS_256 = {
+            0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0,
+            0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
+
+            0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
+            0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
+            0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
+            0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
+            0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
+            0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
+            0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
+            0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
+            0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
+            0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
+            0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
+            0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
+            0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
+            0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
+            0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
+            0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
+            0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
+            0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
+            0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
+            0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
+            0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
+            0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
+            0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
+            0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
+            0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
+            0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
+            0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
+
+            0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
+            0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
+            0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee,
+    };
+
+    /** D50 illuminant for CAM color spaces */
+    public static final double[] D50 = new double[] { 96.422f, 100.0f,  82.521f };
+    /** D65 illuminant for CAM color spaces */
+    public static final double[] D65 = new double[] { 95.047, 100.0, 108.883 };
+
+    /** Average surrounding for CAM color spaces */
+    public static final double[] averageSurrounding = new double[] { 1.0, 0.690, 1.0 };
+    /** Dim surrounding for CAM color spaces */
+    public static final double[] dimSurrounding =     new double[] { 0.9, 0.590, 0.9 };
+    /** Dark surrounding for CAM color spaces */
+    public static final double[] darkSurrounding =    new double[] { 0.8, 0.525, 0.8 };
+
+    /** sRGB encoding environment */
+    public static final double[] sRGB_encoding_environment = vc(D50,  64.0,  64/5, dimSurrounding);
+    /** sRGB typical environment */
+    public static final double[] sRGB_typical_environment  = vc(D50, 200.0, 200/5, averageSurrounding);
+    /** Adobe RGB environment */
+    public static final double[] AdobeRGB_environment      = vc(D65, 160.0, 160/5, averageSurrounding);
+
+    private static int[] COLORS_256 = DEFAULT_COLORS_256;
+
+    private static Map<String, Integer> COLOR_NAMES;
+
+    public static void setRgbColors(int[] colors) {
+        if (colors == null || colors.length != 256) {
+            throw new IllegalArgumentException();
+        }
+        COLORS_256 = colors;
+    }
+
+    public static int rgbColor(int col) {
+        return COLORS_256[col];
+    }
+
+    public static Integer rgbColor(String name) {
+        if (COLOR_NAMES == null) {
+            Map<String, Integer> colors = new LinkedHashMap<>();
+            try (InputStream is = InfoCmp.class.getResourceAsStream("colors.txt");
+                 BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+                br.lines().map(String::trim)
+                        .filter(s -> !s.startsWith("#"))
+                        .filter(s -> !s.isEmpty())
+                        .forEachOrdered(s -> {
+                            colors.put(s, colors.size());
+                        });
+                COLOR_NAMES = colors;
+            } catch (IOException e) {
+                throw new IOError(e);
+            }
+        }
+        return COLOR_NAMES.get(name);
+    }
+
+    public static int roundColor(int col, int max) {
+        return roundColor(col, max, null);
+    }
+
+    public static int roundColor(int col, int max, String dist) {
+        if (col >= max) {
+            int c = COLORS_256[col];
+            col = roundColor(c, COLORS_256, max, dist);
+        }
+        return col;
+    }
+
+    public static int roundRgbColor(int r, int g, int b, int max) {
+        return roundColor((r << 16) + (g << 8) + b, COLORS_256, max, (String) null);
+    }
+
+    private static int roundColor(int color, int[] colors, int max, String dist) {
+        return roundColor(color, colors, max, getDistance(dist));
+    }
+
+    private interface Distance {
+        double compute(int c1, int c2);
+    }
+
+    private static int roundColor(int color, int[] colors, int max, Distance distance) {
+        double best_distance = Integer.MAX_VALUE;
+        int best_index = Integer.MAX_VALUE;
+        for (int idx = 0; idx < max; idx++) {
+            double d = distance.compute(color, colors[idx]);
+            if (d <= best_distance) {
+                best_index = idx;
+                best_distance = d;
+            }
+        }
+        return best_index;
+    }
+
+    private static Distance getDistance(String dist) {
+        if (dist == null) {
+            dist = System.getProperty(PROP_COLOR_DISTANCE, "cie76");
+        }
+        return doGetDistance(dist);
+    }
+
+    private static Distance doGetDistance(String dist) {
+        if (dist.equals("rgb")) {
+            return (p1, p2) -> {
+                // rgb: see https://www.compuphase.com/cmetric.htm
+                double[] c1 = rgb(p1);
+                double[] c2 = rgb(p2);
+                double rmean = (c1[0] + c2[0]) / 2.0;
+                double[] w = { 2.0 + rmean, 4.0, 3.0 - rmean };
+                return scalar(c1, c2, w);
+            };
+        }
+        if (dist.matches("rgb\\(([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?)\\)")) {
+            return (p1, p2) -> scalar(rgb(p1), rgb(p2), getWeights(dist));
+        }
+        if (dist.equals("lab") || dist.equals("cie76")) {
+            return (p1, p2) -> scalar(rgb2cielab(p1), rgb2cielab(p2));
+        }
+        if (dist.matches("lab\\(([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?)\\)")) {
+            double[] w = getWeights(dist);
+            return (p1, p2) -> scalar(rgb2cielab(p1), rgb2cielab(p2), new double[] { w[0], w[1], w[1] });
+        }
+        if (dist.equals("cie94")) {
+            return (p1, p2) -> cie94(rgb2cielab(p1), rgb2cielab(p2));
+        }
+        if (dist.equals("cie00") || dist.equals("cie2000")) {
+            return (p1, p2) -> cie00(rgb2cielab(p1), rgb2cielab(p2));
+        }
+        if (dist.equals("cam02")) {
+            return (p1, p2) -> cam02(p1, p2, sRGB_typical_environment);
+        }
+        if (dist.equals("camlab")) {
+            return (p1, p2) -> {
+                double[] c1 = camlab(p1, sRGB_typical_environment);
+                double[] c2 = camlab(p2, sRGB_typical_environment);
+                return scalar(c1, c2);
+            };
+        }
+        if (dist.matches("camlab\\(([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?)\\)")) {
+            return (p1, p2) -> {
+                double[] c1 = camlab(p1, sRGB_typical_environment);
+                double[] c2 = camlab(p2, sRGB_typical_environment);
+                double[] w = getWeights(dist);
+                return scalar(c1, c2, new double[] { w[0], w[1], w[1] });
+            };
+        }
+        if (dist.matches("camlch")) {
+            return (p1, p2) -> {
+                double[] c1 = camlch(p1, sRGB_typical_environment);
+                double[] c2 = camlch(p2, sRGB_typical_environment);
+                return camlch(c1, c2);
+            };
+        }
+        if (dist.matches("camlch\\(([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?),([0-9]+(\\.[0-9]+)?)\\)")) {
+            return (p1, p2) -> {
+                double[] c1 = camlch(p1, sRGB_typical_environment);
+                double[] c2 = camlch(p2, sRGB_typical_environment);
+                double[] w = getWeights(dist);
+                return camlch(c1, c2, w);
+            };
+        }
+        throw new IllegalArgumentException("Unsupported distance function: " + dist);
+    }
+
+    private static double[] getWeights(String dist) {
+        String[] weights = dist.substring(dist.indexOf('(') + 1, dist.length() - 1).split(",");
+        return Stream.of(weights).mapToDouble(Double::parseDouble).toArray();
+    }
+
+    private static double scalar(double[] c1, double[] c2, double[] w) {
+        return sqr((c1[0] - c2[0]) * w[0])
+             + sqr((c1[1] - c2[1]) * w[1])
+             + sqr((c1[2] - c2[2]) * w[2]);
+    }
+
+    private static double scalar(double[] c1, double[] c2) {
+        return sqr(c1[0] - c2[0])
+             + sqr(c1[1] - c2[1])
+             + sqr(c1[2] - c2[2]);
+    }
+
+    private static final int L = 0;
+    private static final int A = 1;
+    private static final int B = 2;
+    private static final int X = 0;
+    private static final int Y = 1;
+    private static final int Z = 2;
+    private static final double kl = 2.0;
+    private static final double kc = 1.0;
+    private static final double kh = 1.0;
+    private static final double k1 = 0.045;
+    private static final double k2 = 0.015;
+
+    private static double cie94(double[] lab1, double[] lab2) {
+        double dl = lab1[L] - lab2[L];
+        double da = lab1[A] - lab2[A];
+        double db = lab1[B] - lab2[B];
+        double c1 = Math.sqrt(lab1[A] * lab1[A] + lab1[B] * lab1[B]);
+        double c2 = Math.sqrt(lab2[A] * lab2[A] + lab2[B] * lab2[B]);
+        double dc = c1 - c2;
+        double dh = da * da + db * db - dc * dc;
+        dh = dh < 0.0 ? 0.0 : Math.sqrt(dh);
+        double sl = 1.0;
+        double sc = 1.0 + k1 * c1;
+        double sh = 1.0 + k2 * c1;
+        double dLKlsl = dl / (kl * sl);
+        double dCkcsc = dc / (kc * sc);
+        double dHkhsh = dh / (kh * sh);
+        return dLKlsl * dLKlsl + dCkcsc * dCkcsc + dHkhsh * dHkhsh;
+    }
+
+    private static double cie00(double[] lab1, double[] lab2) {
+        double c_star_1_ab = Math.sqrt(lab1[A] * lab1[A] + lab1[B] * lab1[B]);
+        double c_star_2_ab = Math.sqrt(lab2[A] * lab2[A] + lab2[B] * lab2[B]);
+        double c_star_average_ab = (c_star_1_ab + c_star_2_ab) / 2.0;
+        double c_star_average_ab_pot_3 = c_star_average_ab * c_star_average_ab * c_star_average_ab;
+        double c_star_average_ab_pot_7 = c_star_average_ab_pot_3 * c_star_average_ab_pot_3 * c_star_average_ab;
+        double G = 0.5 * (1.0 - Math.sqrt(c_star_average_ab_pot_7 / (c_star_average_ab_pot_7 + 6103515625.0))); //25^7
+        double a1_prime = (1.0 + G) * lab1[A];
+        double a2_prime = (1.0 + G) * lab2[A];
+        double C_prime_1 = Math.sqrt(a1_prime * a1_prime + lab1[B] * lab1[B]);
+        double C_prime_2 = Math.sqrt(a2_prime * a2_prime + lab2[B] * lab2[B]);
+        double h_prime_1 = (Math.toDegrees(Math.atan2(lab1[B], a1_prime)) + 360.0) % 360.0;
+        double h_prime_2 = (Math.toDegrees(Math.atan2(lab2[B], a2_prime)) + 360.0) % 360.0;
+        double delta_L_prime = lab2[L] - lab1[L];
+        double delta_C_prime = C_prime_2 - C_prime_1;
+        double h_bar = Math.abs(h_prime_1 - h_prime_2);
+        double delta_h_prime;
+        if (C_prime_1 * C_prime_2 == 0.0) {
+            delta_h_prime = 0.0;
+        } else if (h_bar <= 180.0) {
+            delta_h_prime = h_prime_2 - h_prime_1;
+        } else if (h_prime_2 <= h_prime_1) {
+            delta_h_prime = h_prime_2 - h_prime_1 + 360.0;
+        } else {
+            delta_h_prime = h_prime_2 - h_prime_1 - 360.0;
+        }
+        double delta_H_prime = 2.0 * Math.sqrt(C_prime_1 * C_prime_2) * Math.sin(Math.toRadians(delta_h_prime / 2.0));
+        double L_prime_average = (lab1[L] + lab2[L]) / 2.0;
+        double C_prime_average = (C_prime_1 + C_prime_2) / 2.0;
+        double h_prime_average;
+        if (C_prime_1 * C_prime_2 == 0.0) {
+            h_prime_average = 0.0;
+        } else if (h_bar <= 180.0) {
+            h_prime_average = (h_prime_1 + h_prime_2) / 2.0;
+        } else if ((h_prime_1 + h_prime_2) < 360.0) {
+            h_prime_average = (h_prime_1 + h_prime_2 + 360.0) / 2.0;
+        } else {
+            h_prime_average = (h_prime_1 + h_prime_2 - 360.0) / 2.0;
+        }
+        double L_prime_average_minus_50 = L_prime_average - 50.0;
+        double L_prime_average_minus_50_square = L_prime_average_minus_50 * L_prime_average_minus_50;
+        double T = 1.0
+                - 0.17 * Math.cos(Math.toRadians(h_prime_average - 30.0))
+                + 0.24 * Math.cos(Math.toRadians(h_prime_average * 2.0))
+                + 0.32 * Math.cos(Math.toRadians(h_prime_average * 3.0 + 6.0))
+                - 0.20 * Math.cos(Math.toRadians(h_prime_average * 4.0 - 63.0));
+        double S_L = 1.0 + ((0.015 * L_prime_average_minus_50_square) / Math.sqrt(20.0 + L_prime_average_minus_50_square));
+        double S_C = 1.0 + 0.045 * C_prime_average;
+        double S_H = 1.0 + 0.015 * T * C_prime_average;
+        double h_prime_average_minus_275_div_25 = (h_prime_average - 275.0) / (25.0);
+        double h_prime_average_minus_275_div_25_square = h_prime_average_minus_275_div_25 * h_prime_average_minus_275_div_25;
+        double delta_theta = 30.0 * Math.exp(-h_prime_average_minus_275_div_25_square);
+        double C_prime_average_pot_3 = C_prime_average * C_prime_average * C_prime_average;
+        double C_prime_average_pot_7 = C_prime_average_pot_3 * C_prime_average_pot_3 * C_prime_average;
+        double R_C = 2.0 * Math.sqrt(C_prime_average_pot_7 / (C_prime_average_pot_7 + 6103515625.0)); //25^7
+        double R_T = - Math.sin(Math.toRadians(2.0 * delta_theta)) * R_C;
+        double dLKlsl = delta_L_prime / (kl * S_L);
+        double dCkcsc = delta_C_prime / (kc * S_C);
+        double dHkhsh = delta_H_prime / (kh * S_H);
+        return dLKlsl * dLKlsl + dCkcsc * dCkcsc + dHkhsh * dHkhsh + R_T * dCkcsc * dHkhsh;
+    }
+
+    private static double cam02(int p1, int p2, double[] vc) {
+        double[] c1 = jmh2ucs(camlch(p1, vc));
+        double[] c2 = jmh2ucs(camlch(p2, vc));
+        return scalar(c1, c2);
+    }
+
+    private static double[] jmh2ucs(double[] lch) {
+        double sJ = ((1.0 + 100 * 0.007) * lch[0]) / (1.0 + 0.007 * lch[0]);
+        double sM = ((1.0 / 0.0228) * Math.log(1.0 + 0.0228 * lch[1]));
+        double a = sM * Math.cos(Math.toRadians(lch[2]));
+        double b = sM * Math.sin(Math.toRadians(lch[2]));
+        return new double[] {sJ, a, b };
+    }
+
+    static double camlch(double[] c1, double[] c2) {
+        return camlch(c1, c2, new double[] { 1.0, 1.0, 1.0 });
+    }
+
+    static double camlch(double[] c1, double[] c2, double[] w) {
+        // normalize weights to correlate range
+        double lightnessWeight = w[0] / 100.0;
+        double colorfulnessWeight = w[1] / 120.0;
+        double hueWeight = w[2] / 360.0;
+        // calculate sort-of polar distance
+        double dl = (c1[0] - c2[0]) * lightnessWeight;
+        double dc = (c1[1] - c2[1]) * colorfulnessWeight;
+        double dh = hueDifference(c1[2], c2[2], 360.0) * hueWeight;
+        return dl * dl + dc * dc + dh * dh;
+    }
+
+    private static double hueDifference(double hue1, double hue2, double c) {
+        double difference = (hue2 - hue1) % c;
+        double ch = c / 2;
+        if (difference > ch)
+            difference -= c;
+        if (difference < -ch)
+            difference += c;
+        return difference;
+    }
+
+    private static double[] rgb(int color) {
+        int r = (color >> 16) & 0xFF;
+        int g = (color >>  8) & 0xFF;
+        int b = (color >>  0) & 0xFF;
+        return new double[] { r / 255.0, g / 255.0, b / 255.0 };
+    }
+
+    static double[] rgb2xyz(int color) {
+        return rgb2xyz(rgb(color));
+    }
+
+    static double[] rgb2cielab(int color) {
+        return rgb2cielab(rgb(color));
+    }
+
+    static double[] camlch(int color) {
+        return camlch(color, sRGB_typical_environment);
+    }
+
+    static double[] camlch(int color, double[] vc) {
+        return xyz2camlch(rgb2xyz(color), vc);
+    }
+
+    static double[] camlab(int color) {
+        return camlab(color, sRGB_typical_environment);
+    }
+
+    static double[] camlab(int color, double[] vc) {
+        return lch2lab(camlch(color, vc));
+    }
+
+    static double[] lch2lab(double[] lch) {
+        double toRad = Math.PI / 180;
+        return new double[] { lch[0], lch[1] * Math.cos(lch[2] * toRad), lch[1] * Math.sin(lch[2] * toRad) };
+    }
+
+    private static double[] xyz2camlch(double[] xyz, double[] vc) {
+        double[] XYZ = new double[] {xyz[0] * 100.0, xyz[1] * 100.0, xyz[2] * 100.0};
+        double[] cam = forwardTransform(XYZ, vc);
+        return new double[] { cam[J], cam[M], cam[h] };
+    }
+
+    /** Lightness */
+    public static final int J = 0;
+    /** Brightness */
+    public static final int Q = 1;
+    /** Chroma */
+    public static final int C = 2;
+    /** Colorfulness */
+    public static final int M = 3;
+    /** Saturation */
+    public static final int s = 4;
+    /** Hue Composition / Hue Quadrature */
+    public static final int H = 5;
+    /** Hue */
+    public static final int h = 6;
+
+
+    /** CIECAM02 appearance correlates */
+    private static double[] forwardTransform(double[] XYZ, double[] vc) {
+        // calculate sharpened cone response
+        double[] RGB = forwardPreAdaptationConeResponse(XYZ);
+        // calculate corresponding (sharpened) cone response considering various luminance level and surround conditions in D
+        double[] RGB_c = forwardPostAdaptationConeResponse(RGB, vc);
+        // calculate HPE equal area cone fundamentals
+        double[] RGBPrime = CAT02toHPE(RGB_c);
+        // calculate response-compressed postadaptation cone response
+        double[] RGBPrime_a = forwardResponseCompression(RGBPrime, vc);
+        // calculate achromatic response
+        double A = (2.0 * RGBPrime_a[0] + RGBPrime_a[1] + RGBPrime_a[2] / 20.0 - 0.305) * vc[VC_N_BB];
+        // calculate lightness
+        double J = 100.0 * Math.pow(A / vc[VC_A_W], vc[VC_Z] * vc[VC_C]);
+        // calculate redness-greenness and yellowness-blueness color opponent values
+        double a = RGBPrime_a[0] + (-12.0 * RGBPrime_a[1] + RGBPrime_a[2]) / 11.0;
+        double b = (RGBPrime_a[0] + RGBPrime_a[1] - 2.0 * RGBPrime_a[2]) / 9.0;
+        // calculate hue angle
+        double h = (Math.toDegrees(Math.atan2(b, a)) + 360.0) % 360.0;
+        // calculate eccentricity
+        double e = ((12500.0 / 13.0) * vc[VC_N_C] * vc[VC_N_CB]) * (Math.cos(Math.toRadians(h) + 2.0) + 3.8);
+        // get t
+        double t = e * Math.sqrt(Math.pow(a, 2.0) + Math.pow(b, 2.0)) / (RGBPrime_a[0] + RGBPrime_a[1] + 1.05 * RGBPrime_a[2]);
+        // calculate brightness
+        double Q = (4.0 / vc[VC_C]) * Math.sqrt(J / 100.0) * (vc[VC_A_W] + 4.0) * Math.pow(vc[VC_F_L], 0.25);
+        // calculate the correlates of chroma, colorfulness, and saturation
+        double C = Math.signum(t) * Math.pow(Math.abs(t), 0.9) * Math.sqrt(J / 100.0) * Math.pow(1.64- Math.pow(0.29, vc[VC_N]), 0.73);
+        double M = C * Math.pow(vc[VC_F_L], 0.25);
+        double s = 100.0 * Math.sqrt(M / Q);
+        // calculate hue composition
+        double H = calculateH(h);
+        return new double[] { J, Q, C, M, s, H, h };
+    }
+
+    private static double calculateH(double h) {
+        if (h < 20.14)
+            h = h + 360;
+        double i;
+        if (h >= 20.14 && h < 90.0) {  // index i = 1
+            i = (h - 20.14) / 0.8;
+            return 100.0 * i / (i + (90 - h) / 0.7);
+        } else if (h < 164.25) { // index i = 2
+            i = (h - 90) / 0.7;
+            return 100.0 + 100.0 * i / (i + (164.25 - h) / 1);
+        } else if (h < 237.53) {  // index i = 3
+            i = (h - 164.25) / 1.0;
+            return 200.0 + 100.0 * i / (i + (237.53 - h) / 1.2);
+        } else if (h <= 380.14) {  // index i = 4
+            i = (h - 237.53) / 1.2;
+            double H = 300.0 + 100.0 * i / (i + (380.14 - h) / 0.8);
+            // don't use 400 if we can use 0
+            if (H <= 400.0 && H >= 399.999)
+                H = 0;
+            return H;
+        } else {
+            throw new IllegalArgumentException("h outside assumed range 0..360: " + Double.toString(h));
+        }
+    }
+
+    private static double[] forwardResponseCompression(double[] RGB, double[] vc) {
+        double[] result = new double[3];
+        for(int channel = 0; channel < RGB.length; channel++) {
+            if(RGB[channel] >= 0) {
+                double n = Math.pow(vc[VC_F_L] * RGB[channel] / 100.0, 0.42);
+                result[channel] = 400.0 * n / (n + 27.13) + 0.1;
+            } else {
+                double n = Math.pow(-1.0 * vc[VC_F_L] * RGB[channel] / 100.0, 0.42);
+                result[channel] = -400.0 * n / (n + 27.13) + 0.1;
+            }
+        }
+        return result;
+    }
+
+    private static double[] forwardPostAdaptationConeResponse(double[] RGB, double[] vc) {
+        return new double[] { vc[VC_D_RGB_R] * RGB[0], vc[VC_D_RGB_G] * RGB[1], vc[VC_D_RGB_B] * RGB[2] };
+    }
+
+    public static double[] CAT02toHPE(double[] RGB) {
+        double[] RGBPrime = new double[3];
+        RGBPrime[0] =  0.7409792 * RGB[0] + 0.2180250 * RGB[1] + 0.0410058 * RGB[2];
+        RGBPrime[1] =  0.2853532 * RGB[0] + 0.6242014 * RGB[1] + 0.0904454 * RGB[2];
+        RGBPrime[2] = -0.0096280 * RGB[0] - 0.0056980 * RGB[1] + 1.0153260 * RGB[2];
+        return RGBPrime;
+    }
+
+    private static double[] forwardPreAdaptationConeResponse(double[] XYZ) {
+        double[] RGB = new double[3];
+        RGB[0] =  0.7328 * XYZ[0] + 0.4296 * XYZ[1] - 0.1624 * XYZ[2];
+        RGB[1] = -0.7036 * XYZ[0] + 1.6975 * XYZ[1] + 0.0061 * XYZ[2];
+        RGB[2] =  0.0030 * XYZ[0] + 0.0136 * XYZ[1] + 0.9834 * XYZ[2];
+        return RGB;
+    }
+
+    static final int SUR_F = 0;
+    static final int SUR_C = 1;
+    static final int SUR_N_C = 2;
+
+    static final int VC_X_W = 0;
+    static final int VC_Y_W = 1;
+    static final int VC_Z_W = 2;
+    static final int VC_L_A = 3;
+    static final int VC_Y_B = 4;
+    static final int VC_F =   5;
+    static final int VC_C =   6;
+    static final int VC_N_C = 7;
+
+    static final int VC_Z = 8;
+    static final int VC_N = 9;
+    static final int VC_N_BB = 10;
+    static final int VC_N_CB = 11;
+    static final int VC_A_W = 12;
+    static final int VC_F_L = 13;
+    static final int VC_D_RGB_R = 14;
+    static final int VC_D_RGB_G = 15;
+    static final int VC_D_RGB_B = 16;
+
+    static double[] vc(double[] xyz_w, double L_A, double Y_b, double[] surrounding) {
+        double[] vc = new double[17];
+        vc[VC_X_W] = xyz_w[0];
+        vc[VC_Y_W] = xyz_w[1];
+        vc[VC_Z_W] = xyz_w[2];
+        vc[VC_L_A] = L_A;
+        vc[VC_Y_B] = Y_b;
+        vc[VC_F] = surrounding[SUR_F];
+        vc[VC_C] = surrounding[SUR_C];
+        vc[VC_N_C] = surrounding[SUR_N_C];
+
+        double[] RGB_w = forwardPreAdaptationConeResponse(xyz_w);
+        double D = Math.max(0.0, Math.min(1.0, vc[VC_F] * (1.0 - (1.0 / 3.6) * Math.pow(Math.E, (-L_A - 42.0) / 92.0))));
+        double Yw = xyz_w[1];
+        double[] RGB_c = new double[] {
+                (D * Yw / RGB_w[0]) + (1.0 - D),
+                (D * Yw / RGB_w[1]) + (1.0 - D),
+                (D * Yw / RGB_w[2]) + (1.0 - D),
+        };
+
+        // calculate increase in brightness and colorfulness caused by brighter viewing environments
+        double L_Ax5 = 5.0 * L_A;
+        double k = 1.0 / (L_Ax5 + 1.0);
+        double kpow4 = Math.pow(k, 4.0);
+        vc[VC_F_L] = 0.2 * kpow4 * (L_Ax5) + 0.1 * Math.pow(1.0 - kpow4, 2.0) * Math.pow(L_Ax5, 1.0/3.0);
+
+        // calculate response compression on J and C caused by background lightness.
+        vc[VC_N] = Y_b / Yw;
+        vc[VC_Z] = 1.48 + Math.sqrt(vc[VC_N]);
+
+        vc[VC_N_BB] = 0.725 * Math.pow(1.0 / vc[VC_N], 0.2);
+        vc[VC_N_CB] = vc[VC_N_BB]; // chromatic contrast factors (calculate increase in J, Q, and C caused by dark backgrounds)
+
+        // calculate achromatic response to white
+        double[] RGB_wc = new double[] {RGB_c[0] * RGB_w[0], RGB_c[1] * RGB_w[1], RGB_c[2] * RGB_w[2]};
+        double[] RGBPrime_w = CAT02toHPE(RGB_wc);
+        double[] RGBPrime_aw = new double[3];
+        for(int channel = 0; channel < RGBPrime_w.length; channel++) {
+            if(RGBPrime_w[channel] >= 0) {
+                double n = Math.pow(vc[VC_F_L] * RGBPrime_w[channel] / 100.0, 0.42);
+                RGBPrime_aw[channel] = 400.0 * n / (n + 27.13) + 0.1;
+            } else {
+                double n = Math.pow(-1.0 * vc[VC_F_L] * RGBPrime_w[channel] / 100.0, 0.42);
+                RGBPrime_aw[channel] = -400.0 * n / (n + 27.13) + 0.1;
+            }
+        }
+        vc[VC_A_W] = (2.0 * RGBPrime_aw[0] + RGBPrime_aw[1] + RGBPrime_aw[2] / 20.0 - 0.305) * vc[VC_N_BB];
+        vc[VC_D_RGB_R] = RGB_c[0];
+        vc[VC_D_RGB_G] = RGB_c[1];
+        vc[VC_D_RGB_B] = RGB_c[2];
+        return vc;
+    }
+
+    public static double[] rgb2cielab(double[] rgb) {
+        return xyz2lab(rgb2xyz(rgb));
+    }
+
+    private static double[] rgb2xyz(double[] rgb) {
+        double vr = pivotRgb(rgb[0]);
+        double vg = pivotRgb(rgb[1]);
+        double vb = pivotRgb(rgb[2]);
+        // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+        double x = vr * 0.4124564 + vg * 0.3575761 + vb * 0.1804375;
+        double y = vr * 0.2126729 + vg * 0.7151522 + vb * 0.0721750;
+        double z = vr * 0.0193339 + vg * 0.1191920 + vb * 0.9503041;
+        return new double[] { x, y, z };
+    }
+
+    private static double pivotRgb(double n) {
+        return n > 0.04045 ? Math.pow((n + 0.055) / 1.055, 2.4) : n / 12.92;
+    }
+
+    private static double[] xyz2lab(double[] xyz) {
+        double fx = pivotXyz(xyz[0]);
+        double fy = pivotXyz(xyz[1]);
+        double fz = pivotXyz(xyz[2]);
+        double l = 116.0 * fy - 16.0;
+        double a = 500.0 * (fx - fy);
+        double b = 200.0 * (fy - fz);
+        return new double[] { l, a, b };
+    }
+
+    private static final double epsilon = 216.0 / 24389.0;
+    private static final double kappa = 24389.0 / 27.0;
+    private static double pivotXyz(double n) {
+        return n > epsilon ? Math.cbrt(n) : (kappa * n + 16) / 116;
+    }
+
+    private static double sqr(double n) {
+        return n * n;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.Flushable;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Stack;
+
+/**
+ * Curses helper methods.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public final class Curses {
+
+    private static Object[] sv = new Object[26];
+    private static Object[] dv = new Object[26];
+
+    private static final int IFTE_NONE = 0;
+    private static final int IFTE_IF = 1;
+    private static final int IFTE_THEN = 2;
+    private static final int IFTE_ELSE = 3;
+
+    private Curses() {
+    }
+
+    /**
+     * Print the given terminal capabilities
+     *
+     * @param cap the capability to output
+     * @param params optional parameters
+     * @return the result string
+     */
+    public static String tputs(String cap, Object... params) {
+        if (cap != null) {
+            StringWriter sw = new StringWriter();
+            tputs(sw, cap, params);
+            return sw.toString();
+        }
+        return null;
+    }
+
+    /**
+     * Print the given terminal capabilities
+     *
+     * @param out the output stream
+     * @param str the capability to output
+     * @param params optional parameters
+     */
+    public static void tputs(Appendable out, String str, Object... params) {
+        try {
+            doTputs(out, str, params);
+        } catch (Exception e) {
+            throw new IOError(e);
+        }
+    }
+
+    private static void doTputs(Appendable out, String str, Object... params) throws IOException {
+        int index = 0;
+        int length = str.length();
+        int ifte = IFTE_NONE;
+        boolean exec = true;
+        Stack<Object> stack = new Stack<>();
+        while (index < length) {
+            char ch = str.charAt(index++);
+            switch (ch) {
+                case '\\':
+                    ch = str.charAt(index++);
+                    if (ch >= '0' && ch <= '9') {
+                        throw new UnsupportedOperationException(); // todo
+                    } else {
+                        switch (ch) {
+                            case 'e':
+                            case 'E':
+                                if (exec) {
+                                    out.append((char) 27); // escape
+                                }
+                                break;
+                            case 'n':
+                                out.append('\n');
+                                break;
+//                        case 'l':
+//                            rawPrint('\l');
+//                            break;
+                            case 'r':
+                                if (exec) {
+                                    out.append('\r');
+                                }
+                                break;
+                            case 't':
+                                if (exec) {
+                                    out.append('\t');
+                                }
+                                break;
+                            case 'b':
+                                if (exec) {
+                                    out.append('\b');
+                                }
+                                break;
+                            case 'f':
+                                if (exec) {
+                                    out.append('\f');
+                                }
+                                break;
+                            case 's':
+                                if (exec) {
+                                    out.append(' ');
+                                }
+                                break;
+                            case ':':
+                            case '^':
+                            case '\\':
+                                if (exec) {
+                                    out.append(ch);
+                                }
+                                break;
+                            default:
+                                throw new IllegalArgumentException();
+                        }
+                    }
+                    break;
+                case '^':
+                    ch = str.charAt(index++);
+                    if (exec) {
+                        out.append((char)(ch - '@'));
+                    }
+                    break;
+                case '%':
+                    ch = str.charAt(index++);
+                    switch (ch) {
+                        case '%':
+                            if (exec) {
+                                out.append('%');
+                            }
+                            break;
+                        case 'p':
+                            ch = str.charAt(index++);
+                            if (exec) {
+                                stack.push(params[ch - '1']);
+                            }
+                            break;
+                        case 'P':
+                            ch = str.charAt(index++);
+                            if (ch >= 'a' && ch <= 'z') {
+                                if (exec) {
+                                    dv[ch - 'a'] = stack.pop();
+                                }
+                            } else if (ch >= 'A' && ch <= 'Z') {
+                                if (exec) {
+                                    sv[ch - 'A'] = stack.pop();
+                                }
+                            } else {
+                                throw new IllegalArgumentException();
+                            }
+                            break;
+                        case 'g':
+                            ch = str.charAt(index++);
+                            if (ch >= 'a' && ch <= 'z') {
+                                if (exec) {
+                                    stack.push(dv[ch - 'a']);
+                                }
+                            } else if (ch >= 'A' && ch <= 'Z') {
+                                if (exec) {
+                                    stack.push(sv[ch - 'A']);
+                                }
+                            } else {
+                                throw new IllegalArgumentException();
+                            }
+                            break;
+                        case '\'':
+                            ch = str.charAt(index++);
+                            if (exec) {
+                                stack.push((int) ch);
+                            }
+                            ch = str.charAt(index++);
+                            if (ch != '\'') {
+                                throw new IllegalArgumentException();
+                            }
+                            break;
+                        case '{':
+                            int start = index;
+                            while (str.charAt(index++) != '}') ;
+                            if (exec) {
+                                int v = Integer.valueOf(str.substring(start, index - 1));
+                                stack.push(v);
+                            }
+                            break;
+                        case 'l':
+                            if (exec) {
+                                stack.push(stack.pop().toString().length());
+                            }
+                            break;
+                        case '+':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 + v2);
+                            }
+                            break;
+                        case '-':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 - v2);
+                            }
+                            break;
+                        case '*':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 * v2);
+                            }
+                            break;
+                        case '/':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 / v2);
+                            }
+                            break;
+                        case 'm':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 % v2);
+                            }
+                            break;
+                        case '&':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 & v2);
+                            }
+                            break;
+                        case '|':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 | v2);
+                            }
+                            break;
+                        case '^':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 ^ v2);
+                            }
+                            break;
+                        case '=':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 == v2);
+                            }
+                            break;
+                        case '>':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 > v2);
+                            }
+                            break;
+                        case '<':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 < v2);
+                            }
+                            break;
+                        case 'A':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 != 0 && v2 != 0);
+                            }
+                            break;
+                        case '!':
+                            if (exec) {
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 == 0);
+                            }
+                            break;
+                        case '~':
+                            if (exec) {
+                                int v1 = toInteger(stack.pop());
+                                stack.push(~v1);
+                            }
+                            break;
+                        case 'O':
+                            if (exec) {
+                                int v2 = toInteger(stack.pop());
+                                int v1 = toInteger(stack.pop());
+                                stack.push(v1 != 0 || v2 != 0);
+                            }
+                            break;
+                        case '?':
+                            if (ifte != IFTE_NONE) {
+                                throw new IllegalArgumentException();
+                            } else {
+                                ifte = IFTE_IF;
+                            }
+                            break;
+                        case 't':
+                            if (ifte != IFTE_IF && ifte != IFTE_ELSE) {
+                                throw new IllegalArgumentException();
+                            } else {
+                                ifte = IFTE_THEN;
+                            }
+                            exec = toInteger(stack.pop()) != 0;
+                            break;
+                        case 'e':
+                            if (ifte != IFTE_THEN) {
+                                throw new IllegalArgumentException();
+                            } else {
+                                ifte = IFTE_ELSE;
+                            }
+                            exec = !exec;
+                            break;
+                        case ';':
+                            if (ifte == IFTE_NONE || ifte == IFTE_IF) {
+                                throw new IllegalArgumentException();
+                            } else {
+                                ifte = IFTE_NONE;
+                            }
+                            exec = true;
+                            break;
+                        case 'i':
+                            if (params.length >= 1) {
+                                params[0] = toInteger(params[0]) + 1;
+                            }
+                            if (params.length >= 2) {
+                                params[1] = toInteger(params[1]) + 1;
+                            }
+                            break;
+                        case 'd':
+                            out.append(Integer.toString(toInteger(stack.pop())));
+                            break;
+                        default:
+                            throw new UnsupportedOperationException();
+                    }
+                    break;
+                case '$':
+                    if (str.charAt(index) == '<') {
+                        // We don't honour delays, just skip
+                        int nb = 0;
+                        while ((ch = str.charAt(++index)) != '>') {
+                            if (ch >= '0' && ch <= '9') {
+                                nb = nb * 10 + (ch - '0');
+                            } else if (ch == '*') {
+                                // ignore
+                            } else if (ch == '/') {
+                                // ignore
+                            } else {
+                                // illegal, but ...
+                            }
+                        }
+                        index++;
+                        try {
+                            if (out instanceof Flushable) {
+                                ((Flushable) out).flush();
+                            }
+                            Thread.sleep(nb);
+                        } catch (InterruptedException e) {
+                        }
+                    } else {
+                        if (exec) {
+                            out.append(ch);
+                        }
+                    }
+                    break;
+                default:
+                    if (exec) {
+                        out.append(ch);
+                    }
+                    break;
+            }
+        }
+    }
+
+    private static int toInteger(Object pop) {
+        if (pop instanceof Number) {
+            return ((Number) pop).intValue();
+        } else if (pop instanceof Boolean) {
+            return (Boolean) pop ? 1 : 0;
+        } else {
+            return Integer.valueOf(pop.toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/DiffHelper.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,134 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class containing the diff method.
+ * This diff is ANSI aware and will correctly handle text attributes
+ * so that any text in a Diff object is a valid ansi string.
+ */
+public class DiffHelper {
+
+    /**
+     * The data structure representing a diff is a Linked list of Diff objects:
+     * {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"),
+     *  Diff(Operation.EQUAL, " world.")}
+     * which means: delete "Hello", add "Goodbye" and keep " world."
+     */
+    public enum Operation {
+        DELETE, INSERT, EQUAL
+    }
+
+    /**
+     * Class representing one diff operation.
+     */
+    public static class Diff {
+        /**
+         * One of: INSERT, DELETE or EQUAL.
+         */
+        public final Operation operation;
+        /**
+         * The text associated with this diff operation.
+         */
+        public final AttributedString text;
+
+        /**
+         * Constructor.  Initializes the diff with the provided values.
+         * @param operation One of INSERT, DELETE or EQUAL.
+         * @param text The text being applied.
+         */
+        public Diff(Operation operation, AttributedString text) {
+            // Construct a diff with the specified operation and text.
+            this.operation = operation;
+            this.text = text;
+        }
+
+        /**
+         * Display a human-readable version of this Diff.
+         * @return text version.
+         */
+        public String toString() {
+            return "Diff(" + this.operation + ",\"" + this.text + "\")";
+        }
+    }
+
+    /**
+     * Compute a list of difference between two lines.
+     * The result will contain at most 4 Diff objects, as the method
+     * aims to return the common prefix, inserted text, deleted text and
+     * common suffix.
+     * The computation is done on characters and their attributes expressed
+     * as ansi sequences.
+     *
+     * @param text1 the old line
+     * @param text2 the new line
+     * @return a list of Diff
+     */
+    public static List<Diff> diff(AttributedString text1, AttributedString text2) {
+        int l1 = text1.length();
+        int l2 = text2.length();
+        int n = Math.min(l1, l2);
+        int commonStart = 0;
+        // Given a run of contiguous "hidden" characters (which are
+        // sequences of uninterrupted escape sequences) we always want to
+        // print either the entire run or none of it - never a part of it.
+        int startHiddenRange = -1;
+        while (commonStart < n
+                && text1.charAt(commonStart) == text2.charAt(commonStart)
+                && text1.styleAt(commonStart).equals(text2.styleAt(commonStart))) {
+            if (text1.isHidden(commonStart)) {
+                if (startHiddenRange < 0)
+                    startHiddenRange = commonStart;
+            } else
+                startHiddenRange = -1;
+            commonStart++;
+        }
+        if (startHiddenRange >= 0
+            && ((l1 > commonStart && text1.isHidden(commonStart))
+                || (l2 > commonStart && text2.isHidden(commonStart))))
+            commonStart = startHiddenRange;
+
+        startHiddenRange = -1;
+        int commonEnd = 0;
+        while (commonEnd < n - commonStart
+                && text1.charAt(l1 - commonEnd - 1) == text2.charAt(l2 - commonEnd - 1)
+                && text1.styleAt(l1 - commonEnd - 1).equals(text2.styleAt(l2 - commonEnd - 1))) {
+            if (text1.isHidden(l1 - commonEnd - 1)) {
+                if (startHiddenRange < 0)
+                    startHiddenRange = commonEnd;
+            } else
+                startHiddenRange = -1;
+            commonEnd++;
+        }
+        if (startHiddenRange >= 0)
+            commonEnd = startHiddenRange;
+        LinkedList<Diff> diffs = new LinkedList<>();
+        if (commonStart > 0) {
+            diffs.add(new Diff(DiffHelper.Operation.EQUAL,
+                    text1.subSequence(0, commonStart)));
+        }
+        if (l2 > commonStart + commonEnd) {
+            diffs.add(new Diff(DiffHelper.Operation.INSERT,
+                    text2.subSequence(commonStart, l2 - commonEnd)));
+        }
+        if (l1 > commonStart + commonEnd) {
+            diffs.add(new Diff(DiffHelper.Operation.DELETE,
+                    text1.subSequence(commonStart, l1 - commonEnd)));
+        }
+        if (commonEnd > 0) {
+            diffs.add(new Diff(DiffHelper.Operation.EQUAL,
+                    text1.subSequence(l1 - commonEnd, l1)));
+        }
+        return diffs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+
+/**
+ * Handle display and visual cursor.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class Display {
+
+    /**OpenJDK:
+     * When true, when the cursor is moved to column 0, carriage_return capability is not used,
+     * but rather the cursor is moved left the appropriate number of positions.
+     * This is useful when there's something already printed on the first line (which is not
+     * specified as a prompt), for example when the user is providing an input.
+     */
+    public static boolean DISABLE_CR = false;
+
+    protected final Terminal terminal;
+    protected final boolean fullScreen;
+    protected List<AttributedString> oldLines = Collections.emptyList();
+    protected int cursorPos;
+    private int columns;
+    private int columns1; // columns+1
+    protected int rows;
+    protected boolean reset;
+    protected boolean delayLineWrap;
+
+    protected final Map<Capability, Integer> cost = new HashMap<>();
+    protected final boolean canScroll;
+    protected final boolean wrapAtEol;
+    protected final boolean delayedWrapAtEol;
+    protected final boolean cursorDownIsNewLine;
+
+    public Display(Terminal terminal, boolean fullscreen) {
+        this.terminal = terminal;
+        this.fullScreen = fullscreen;
+
+        this.canScroll = can(Capability.insert_line, Capability.parm_insert_line)
+                            && can(Capability.delete_line, Capability.parm_delete_line);
+        this.wrapAtEol = terminal.getBooleanCapability(Capability.auto_right_margin);
+        this.delayedWrapAtEol = this.wrapAtEol
+            && terminal.getBooleanCapability(Capability.eat_newline_glitch);
+        this.cursorDownIsNewLine = "\n".equals(Curses.tputs(terminal.getStringCapability(Capability.cursor_down)));
+    }
+
+    /**
+     * If cursor is at right margin, don't wrap immediately.
+     * See <code>org.jline.reader.LineReader.Option#DELAY_LINE_WRAP</code>.
+     * @return <code>true</code> if line wrap is delayed, <code>false</code> otherwise
+     */
+    public boolean delayLineWrap() {
+        return delayLineWrap;
+    }
+    public void setDelayLineWrap(boolean v) { delayLineWrap = v; }
+
+    public void resize(int rows, int columns) {
+        if (this.rows != rows || this.columns != columns) {
+            this.rows = rows;
+            this.columns = columns;
+            this.columns1 = columns + 1;
+            oldLines = AttributedString.join(AttributedString.EMPTY, oldLines).columnSplitLength(columns, true, delayLineWrap());
+        }
+    }
+
+    public void reset() {
+        oldLines = Collections.emptyList();
+    }
+
+    /**
+     * Clears the whole screen.
+     * Use this method only when using full-screen / application mode.
+     */
+    public void clear() {
+        if (fullScreen) {
+            reset = true;
+        }
+    }
+
+    public void updateAnsi(List<String> newLines, int targetCursorPos) {
+        update(newLines.stream().map(AttributedString::fromAnsi).collect(Collectors.toList()), targetCursorPos);
+    }
+
+    /**
+     * Update the display according to the new lines and flushes the output.
+     * @param newLines the lines to display
+     * @param targetCursorPos desired cursor position - see Size.cursorPos.
+     */
+    public void update(List<AttributedString> newLines, int targetCursorPos) {
+        update(newLines, targetCursorPos, true);
+    }
+
+    /**
+     * Update the display according to the new lines.
+     * @param newLines the lines to display
+     * @param targetCursorPos desired cursor position - see Size.cursorPos.
+     * @param flush whether the output should be flushed or not
+     */
+    public void update(List<AttributedString> newLines, int targetCursorPos, boolean flush) {
+        if (reset) {
+            terminal.puts(Capability.clear_screen);
+            oldLines.clear();
+            cursorPos = 0;
+            reset = false;
+        }
+
+        // If dumb display, get rid of ansi sequences now
+        Integer cols = terminal.getNumericCapability(Capability.max_colors);
+        if (cols == null || cols < 8) {
+            newLines = newLines.stream().map(s -> new AttributedString(s.toString()))
+                    .collect(Collectors.toList());
+        }
+
+        // Detect scrolling
+        if ((fullScreen || newLines.size() >= rows) && newLines.size() == oldLines.size() && canScroll) {
+            int nbHeaders = 0;
+            int nbFooters = 0;
+            // Find common headers and footers
+            int l = newLines.size();
+            while (nbHeaders < l
+                   && Objects.equals(newLines.get(nbHeaders), oldLines.get(nbHeaders))) {
+                nbHeaders++;
+            }
+            while (nbFooters < l - nbHeaders - 1
+                    && Objects.equals(newLines.get(newLines.size() - nbFooters - 1), oldLines.get(oldLines.size() - nbFooters - 1))) {
+                nbFooters++;
+            }
+            List<AttributedString> o1 = newLines.subList(nbHeaders, newLines.size() - nbFooters);
+            List<AttributedString> o2 = oldLines.subList(nbHeaders, oldLines.size() - nbFooters);
+            int[] common = longestCommon(o1, o2);
+            if (common != null) {
+                int s1 = common[0];
+                int s2 = common[1];
+                int sl = common[2];
+                if (sl > 1 && s1 < s2) {
+                    moveVisualCursorTo((nbHeaders + s1) * columns1);
+                    int nb = s2 - s1;
+                    deleteLines(nb);
+                    for (int i = 0; i < nb; i++) {
+                        oldLines.remove(nbHeaders + s1);
+                    }
+                    if (nbFooters > 0) {
+                        moveVisualCursorTo((nbHeaders + s1 + sl) * columns1);
+                        insertLines(nb);
+                        for (int i = 0; i < nb; i++) {
+                            oldLines.add(nbHeaders + s1 + sl, new AttributedString(""));
+                        }
+                    }
+                } else if (sl > 1 && s1 > s2) {
+                    int nb = s1 - s2;
+                    if (nbFooters > 0) {
+                        moveVisualCursorTo((nbHeaders + s2 + sl) * columns1);
+                        deleteLines(nb);
+                        for (int i = 0; i < nb; i++) {
+                            oldLines.remove(nbHeaders + s2 + sl);
+                        }
+                    }
+                    moveVisualCursorTo((nbHeaders + s2) * columns1);
+                    insertLines(nb);
+                    for (int i = 0; i < nb; i++) {
+                        oldLines.add(nbHeaders + s2, new AttributedString(""));
+                    }
+                }
+            }
+        }
+
+        int lineIndex = 0;
+        int currentPos = 0;
+        int numLines = Math.max(oldLines.size(), newLines.size());
+        boolean wrapNeeded = false;
+        while (lineIndex < numLines) {
+            AttributedString oldLine =
+                lineIndex < oldLines.size() ? oldLines.get(lineIndex)
+                : AttributedString.NEWLINE;
+            AttributedString newLine =
+                 lineIndex < newLines.size() ? newLines.get(lineIndex)
+                : AttributedString.NEWLINE;
+            currentPos = lineIndex * columns1;
+            int curCol = currentPos;
+            int oldLength = oldLine.length();
+            int newLength = newLine.length();
+            boolean oldNL = oldLength > 0 && oldLine.charAt(oldLength-1)=='\n';
+            boolean newNL = newLength > 0 && newLine.charAt(newLength-1)=='\n';
+            if (oldNL) {
+                oldLength--;
+                oldLine = oldLine.substring(0, oldLength);
+            }
+            if (newNL) {
+                newLength--;
+                newLine = newLine.substring(0, newLength);
+            }
+            if (wrapNeeded
+                && lineIndex == (cursorPos + 1) / columns1
+                && lineIndex < newLines.size()) {
+                // move from right margin to next line's left margin
+                cursorPos++;
+                if (newLength == 0 || newLine.isHidden(0)) {
+                    // go to next line column zero
+                    rawPrint(new AttributedString(" \b"));
+                } else {
+                    AttributedString firstChar =
+                        newLine.columnSubSequence(0, 1);
+                    // go to next line column one
+                    rawPrint(firstChar);
+                    cursorPos++;
+                    int firstLength = firstChar.length(); // normally 1
+                    newLine = newLine.substring(firstLength, newLength);
+                    newLength -= firstLength;
+                    if (oldLength >= firstLength) {
+                        oldLine = oldLine.substring(firstLength, oldLength);
+                        oldLength -= firstLength;
+                    }
+                    currentPos = cursorPos;
+                }
+            }
+            List<DiffHelper.Diff> diffs = DiffHelper.diff(oldLine, newLine);
+            boolean ident = true;
+            boolean cleared = false;
+            for (int i = 0; i < diffs.size(); i++) {
+                DiffHelper.Diff diff = diffs.get(i);
+                int width = diff.text.columnLength();
+                switch (diff.operation) {
+                    case EQUAL:
+                        if (!ident) {
+                            cursorPos = moveVisualCursorTo(currentPos);
+                            rawPrint(diff.text);
+                            cursorPos += width;
+                            currentPos = cursorPos;
+                        } else {
+                            currentPos += width;
+                        }
+                        break;
+                    case INSERT:
+                        if (i <= diffs.size() - 2
+                                && diffs.get(i + 1).operation == DiffHelper.Operation.EQUAL) {
+                            cursorPos = moveVisualCursorTo(currentPos);
+                            if (insertChars(width)) {
+                                rawPrint(diff.text);
+                                cursorPos += width;
+                                currentPos = cursorPos;
+                                break;
+                            }
+                        } else if (i <= diffs.size() - 2
+                                && diffs.get(i + 1).operation == DiffHelper.Operation.DELETE
+                                && width == diffs.get(i + 1).text.columnLength()) {
+                            moveVisualCursorTo(currentPos);
+                            rawPrint(diff.text);
+                            cursorPos += width;
+                            currentPos = cursorPos;
+                            i++; // skip delete
+                            break;
+                        }
+                        moveVisualCursorTo(currentPos);
+                        rawPrint(diff.text);
+                        cursorPos += width;
+                        currentPos = cursorPos;
+                        ident = false;
+                        break;
+                    case DELETE:
+                        if (cleared) {
+                            continue;
+                        }
+                        if (currentPos - curCol >= columns) {
+                            continue;
+                        }
+                        if (i <= diffs.size() - 2
+                                && diffs.get(i + 1).operation == DiffHelper.Operation.EQUAL) {
+                            if (currentPos + diffs.get(i + 1).text.columnLength() < columns) {
+                                moveVisualCursorTo(currentPos);
+                                if (deleteChars(width)) {
+                                    break;
+                                }
+                            }
+                        }
+                        int oldLen = oldLine.columnLength();
+                        int newLen = newLine.columnLength();
+                        int nb = Math.max(oldLen, newLen) - (currentPos - curCol);
+                        moveVisualCursorTo(currentPos);
+                        if (!terminal.puts(Capability.clr_eol)) {
+                            rawPrint(' ', nb);
+                            cursorPos += nb;
+                        }
+                        cleared = true;
+                        ident = false;
+                        break;
+                }
+            }
+            lineIndex++;
+            boolean newWrap = ! newNL && lineIndex < newLines.size();
+            if (targetCursorPos + 1 == lineIndex * columns1
+                && (newWrap || ! delayLineWrap))
+                targetCursorPos++;
+            boolean atRight = (cursorPos - curCol) % columns1 == columns;
+            wrapNeeded = false;
+            if (this.delayedWrapAtEol) {
+                boolean oldWrap = ! oldNL && lineIndex < oldLines.size();
+                if (newWrap != oldWrap && ! (oldWrap && cleared)) {
+                    moveVisualCursorTo(lineIndex*columns1-1, newLines);
+                    if (newWrap)
+                        wrapNeeded = true;
+                    else
+                        terminal.puts(Capability.clr_eol);
+                }
+            } else if (atRight) {
+                if (this.wrapAtEol) {
+                    terminal.writer().write(" \b");
+                    cursorPos++;
+                } else {
+                    terminal.puts(Capability.carriage_return); // CR / not newline.
+                    cursorPos = curCol;
+                }
+                currentPos = cursorPos;
+            }
+        }
+        int was = cursorPos;
+        if (cursorPos != targetCursorPos) {
+            moveVisualCursorTo(targetCursorPos < 0 ? currentPos : targetCursorPos, newLines);
+        }
+        oldLines = newLines;
+
+        if (flush) {
+            terminal.flush();
+        }
+    }
+
+    protected boolean deleteLines(int nb) {
+        return perform(Capability.delete_line, Capability.parm_delete_line, nb);
+    }
+
+    protected boolean insertLines(int nb) {
+        return perform(Capability.insert_line, Capability.parm_insert_line, nb);
+    }
+
+    protected boolean insertChars(int nb) {
+        return perform(Capability.insert_character, Capability.parm_ich, nb);
+    }
+
+    protected boolean deleteChars(int nb) {
+        return perform(Capability.delete_character, Capability.parm_dch, nb);
+    }
+
+    protected boolean can(Capability single, Capability multi) {
+        return terminal.getStringCapability(single) != null
+                || terminal.getStringCapability(multi) != null;
+    }
+
+    protected boolean perform(Capability single, Capability multi, int nb) {
+        boolean hasMulti = terminal.getStringCapability(multi) != null;
+        boolean hasSingle = terminal.getStringCapability(single) != null;
+        if (hasMulti && (!hasSingle || cost(single) * nb > cost(multi))) {
+            terminal.puts(multi, nb);
+            return true;
+        } else if (hasSingle) {
+            for (int i = 0; i < nb; i++) {
+                terminal.puts(single);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private int cost(Capability cap) {
+        return cost.computeIfAbsent(cap, this::computeCost);
+    }
+
+    private int computeCost(Capability cap) {
+        String s = Curses.tputs(terminal.getStringCapability(cap), 0);
+        return s != null ? s.length() : Integer.MAX_VALUE;
+    }
+
+    private static int[] longestCommon(List<AttributedString> l1, List<AttributedString> l2) {
+        int start1 = 0;
+        int start2 = 0;
+        int max = 0;
+        for (int i = 0; i < l1.size(); i++) {
+            for (int j = 0; j < l2.size(); j++) {
+                int x = 0;
+                while (Objects.equals(l1.get(i + x), l2.get(j + x))) {
+                    x++;
+                    if (((i + x) >= l1.size()) || ((j + x) >= l2.size())) break;
+                }
+                if (x > max) {
+                    max = x;
+                    start1 = i;
+                    start2 = j;
+                }
+            }
+        }
+        return max != 0 ? new int[] { start1, start2, max } : null;
+    }
+
+    /*
+     * Move cursor from cursorPos to argument, updating cursorPos
+     * We're at the right margin if {@code (cursorPos % columns1) == columns}.
+     * This method knows how to move both *from* and *to* the right margin.
+     */
+    protected void moveVisualCursorTo(int targetPos,
+                                      List<AttributedString> newLines) {
+        if (cursorPos != targetPos) {
+            boolean atRight = (targetPos % columns1) == columns;
+            moveVisualCursorTo(targetPos - (atRight ? 1 : 0));
+            if (atRight) {
+                // There is no portable way to move to the right margin
+                // except by writing a character in the right-most column.
+                int row = targetPos / columns1;
+                AttributedString lastChar = row >= newLines.size() ? AttributedString.EMPTY
+                    : newLines.get(row).columnSubSequence(columns-1, columns);
+                if (lastChar.length() == 0)
+                    rawPrint((int) ' ');
+                else
+                    rawPrint(lastChar);
+                cursorPos++;
+            }
+        }
+    }
+
+    /*
+     * Move cursor from cursorPos to argument, updating cursorPos
+     * We're at the right margin if {@code (cursorPos % columns1) == columns}.
+     * This method knows how to move *from* the right margin,
+     * but does not know how to move *to* the right margin.
+     * I.e. {@code (i1 % columns1) == column} is not allowed.
+     */
+    protected int moveVisualCursorTo(int i1) {
+        int i0 = cursorPos;
+        if (i0 == i1) return i1;
+        int width = columns1;
+        int l0 = i0 / width;
+        int c0 = i0 % width;
+        int l1 = i1 / width;
+        int c1 = i1 % width;
+        if (c0 == columns) { // at right margin
+            terminal.puts(Capability.carriage_return);
+            c0 = 0;
+        }
+        if (l0 > l1) {
+            perform(Capability.cursor_up, Capability.parm_up_cursor, l0 - l1);
+        } else if (l0 < l1) {
+            // TODO: clean the following
+            if (fullScreen) {
+                if (!terminal.puts(Capability.parm_down_cursor, l1 - l0)) {
+                    for (int i = l0; i < l1; i++) {
+                        terminal.puts(Capability.cursor_down);
+                    }
+                    if (cursorDownIsNewLine) {
+                        c0 = 0;
+                    }
+                }
+            } else {
+                terminal.puts(Capability.carriage_return);
+                rawPrint('\n', l1 - l0);
+                c0 = 0;
+            }
+        }
+        if (c0 != 0 && c1 == 0 && !DISABLE_CR) {
+            terminal.puts(Capability.carriage_return);
+        } else if (c0 < c1) {
+            perform(Capability.cursor_right, Capability.parm_right_cursor, c1 - c0);
+        } else if (c0 > c1) {
+            perform(Capability.cursor_left, Capability.parm_left_cursor, c0 - c1);
+        }
+        cursorPos = i1;
+        return i1;
+    }
+
+    void rawPrint(char c, int num) {
+        for (int i = 0; i < num; i++) {
+            rawPrint(c);
+        }
+    }
+
+    void rawPrint(int c) {
+        terminal.writer().write(c);
+    }
+
+    void rawPrint(AttributedString str) {
+        terminal.writer().write(str.toAnsi(terminal));
+    }
+
+    public int wcwidth(String str) {
+        return AttributedString.fromAnsi(str).columnLength();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ExecHelper.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,86 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.util.Objects;
+
+/**
+ * Helper methods for running unix commands.
+ */
+public final class ExecHelper {
+
+    private ExecHelper() {
+    }
+
+    public static String exec(boolean redirectInput, final String... cmd) throws IOException {
+        Objects.requireNonNull(cmd);
+        try {
+            Log.trace("Running: ", cmd);
+            ProcessBuilder pb = new ProcessBuilder(cmd);
+            if (redirectInput) {
+                pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
+            }
+            Process p = pb.start();
+            String result = waitAndCapture(p);
+            Log.trace("Result: ", result);
+            if (p.exitValue() != 0) {
+                if (result.endsWith("\n")) {
+                    result = result.substring(0, result.length() - 1);
+                }
+                throw new IOException("Error executing '" + String.join(" ", (CharSequence[]) cmd) + "': " + result);
+            }
+            return result;
+        } catch (InterruptedException e) {
+            throw (IOException) new InterruptedIOException("Command interrupted").initCause(e);
+        }
+    }
+
+    public static String waitAndCapture(Process p) throws IOException, InterruptedException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        InputStream in = null;
+        InputStream err = null;
+        OutputStream out = null;
+        try {
+            int c;
+            in = p.getInputStream();
+            while ((c = in.read()) != -1) {
+                bout.write(c);
+            }
+            err = p.getErrorStream();
+            while ((c = err.read()) != -1) {
+                bout.write(c);
+            }
+            out = p.getOutputStream();
+            p.waitFor();
+        } finally {
+            close(in, out, err);
+        }
+
+        return bout.toString();
+    }
+
+    private static void close(final Closeable... closeables) {
+        for (Closeable c : closeables) {
+            if (c != null) {
+                try {
+                    c.close();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,623 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.BufferedReader;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Infocmp helper methods.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public final class InfoCmp {
+
+    private static final Map<String, Object> CAPS = new HashMap<>();
+
+    private InfoCmp() {
+    }
+
+    @SuppressWarnings("unused")
+    public enum Capability {
+
+        auto_left_margin,           // auto_left_margin, bw, bw
+        auto_right_margin,          // auto_right_margin, am, am
+        back_color_erase,           // back_color_erase, bce, ut
+        can_change,                 // can_change, ccc, cc
+        ceol_standout_glitch,       // ceol_standout_glitch, xhp, xs
+        col_addr_glitch,            // col_addr_glitch, xhpa, YA
+        cpi_changes_res,            // cpi_changes_res, cpix, YF
+        cr_cancels_micro_mode,      // cr_cancels_micro_mode, crxm, YB
+        dest_tabs_magic_smso,       // dest_tabs_magic_smso, xt, xt
+        eat_newline_glitch,         // eat_newline_glitch, xenl, xn
+        erase_overstrike,           // erase_overstrike, eo, eo
+        generic_type,               // generic_type, gn, gn
+        hard_copy,                  // hard_copy, hc, hc
+        hard_cursor,                // hard_cursor, chts, HC
+        has_meta_key,               // has_meta_key, km, km
+        has_print_wheel,            // has_print_wheel, daisy, YC
+        has_status_line,            // has_status_line, hs, hs
+        hue_lightness_saturation,   // hue_lightness_saturation, hls, hl
+        insert_null_glitch,         // insert_null_glitch, in, in
+        lpi_changes_res,            // lpi_changes_res, lpix, YG
+        memory_above,               // memory_above, da, da
+        memory_below,               // memory_below, db, db
+        move_insert_mode,           // move_insert_mode, mir, mi
+        move_standout_mode,         // move_standout_mode, msgr, ms
+        needs_xon_xoff,             // needs_xon_xoff, nxon, nx
+        no_esc_ctlc,                // no_esc_ctlc, xsb, xb
+        no_pad_char,                // no_pad_char, npc, NP
+        non_dest_scroll_region,     // non_dest_scroll_region, ndscr, ND
+        non_rev_rmcup,              // non_rev_rmcup, nrrmc, NR
+        over_strike,                // over_strike, os, os
+        prtr_silent,                // prtr_silent, mc5i, 5i
+        row_addr_glitch,            // row_addr_glitch, xvpa, YD
+        semi_auto_right_margin,     // semi_auto_right_margin, sam, YE
+        status_line_esc_ok,         // status_line_esc_ok, eslok, es
+        tilde_glitch,               // tilde_glitch, hz, hz
+        transparent_underline,      // transparent_underline, ul, ul
+        xon_xoff,                   // xon_xoff, xon, xo
+        columns,                    // columns, cols, co
+        init_tabs,                  // init_tabs, it, it
+        label_height,               // label_height, lh, lh
+        label_width,                // label_width, lw, lw
+        lines,                      // lines, lines, li
+        lines_of_memory,            // lines_of_memory, lm, lm
+        magic_cookie_glitch,        // magic_cookie_glitch, xmc, sg
+        max_attributes,             // max_attributes, ma, ma
+        max_colors,                 // max_colors, colors, Co
+        max_pairs,                  // max_pairs, pairs, pa
+        maximum_windows,            // maximum_windows, wnum, MW
+        no_color_video,             // no_color_video, ncv, NC
+        num_labels,                 // num_labels, nlab, Nl
+        padding_baud_rate,          // padding_baud_rate, pb, pb
+        virtual_terminal,           // virtual_terminal, vt, vt
+        width_status_line,          // width_status_line, wsl, ws
+        bit_image_entwining,        // bit_image_entwining, bitwin, Yo
+        bit_image_type,             // bit_image_type, bitype, Yp
+        buffer_capacity,            // buffer_capacity, bufsz, Ya
+        buttons,                    // buttons, btns, BT
+        dot_horz_spacing,           // dot_horz_spacing, spinh, Yc
+        dot_vert_spacing,           // dot_vert_spacing, spinv, Yb
+        max_micro_address,          // max_micro_address, maddr, Yd
+        max_micro_jump,             // max_micro_jump, mjump, Ye
+        micro_col_size,             // micro_col_size, mcs, Yf
+        micro_line_size,            // micro_line_size, mls, Yg
+        number_of_pins,             // number_of_pins, npins, Yh
+        output_res_char,            // output_res_char, orc, Yi
+        output_res_horz_inch,       // output_res_horz_inch, orhi, Yk
+        output_res_line,            // output_res_line, orl, Yj
+        output_res_vert_inch,       // output_res_vert_inch, orvi, Yl
+        print_rate,                 // print_rate, cps, Ym
+        wide_char_size,             // wide_char_size, widcs, Yn
+        acs_chars,                  // acs_chars, acsc, ac
+        back_tab,                   // back_tab, cbt, bt
+        bell,                       // bell, bel, bl
+        carriage_return,            // carriage_return, cr, cr
+        change_char_pitch,          // change_char_pitch, cpi, ZA
+        change_line_pitch,          // change_line_pitch, lpi, ZB
+        change_res_horz,            // change_res_horz, chr, ZC
+        change_res_vert,            // change_res_vert, cvr, ZD
+        change_scroll_region,       // change_scroll_region, csr, cs
+        char_padding,               // char_padding, rmp, rP
+        clear_all_tabs,             // clear_all_tabs, tbc, ct
+        clear_margins,              // clear_margins, mgc, MC
+        clear_screen,               // clear_screen, clear, cl
+        clr_bol,                    // clr_bol, el1, cb
+        clr_eol,                    // clr_eol, el, ce
+        clr_eos,                    // clr_eos, ed, cd
+        column_address,             // column_address, hpa, ch
+        command_character,          // command_character, cmdch, CC
+        create_window,              // create_window, cwin, CW
+        cursor_address,             // cursor_address, cup, cm
+        cursor_down,                // cursor_down, cud1, do
+        cursor_home,                // cursor_home, home, ho
+        cursor_invisible,           // cursor_invisible, civis, vi
+        cursor_left,                // cursor_left, cub1, le
+        cursor_mem_address,         // cursor_mem_address, mrcup, CM
+        cursor_normal,              // cursor_normal, cnorm, ve
+        cursor_right,               // cursor_right, cuf1, nd
+        cursor_to_ll,               // cursor_to_ll, ll, ll
+        cursor_up,                  // cursor_up, cuu1, up
+        cursor_visible,             // cursor_visible, cvvis, vs
+        define_char,                // define_char, defc, ZE
+        delete_character,           // delete_character, dch1, dc
+        delete_line,                // delete_line, dl1, dl
+        dial_phone,                 // dial_phone, dial, DI
+        dis_status_line,            // dis_status_line, dsl, ds
+        display_clock,              // display_clock, dclk, DK
+        down_half_line,             // down_half_line, hd, hd
+        ena_acs,                    // ena_acs, enacs, eA
+        enter_alt_charset_mode,     // enter_alt_charset_mode, smacs, as
+        enter_am_mode,              // enter_am_mode, smam, SA
+        enter_blink_mode,           // enter_blink_mode, blink, mb
+        enter_bold_mode,            // enter_bold_mode, bold, md
+        enter_ca_mode,              // enter_ca_mode, smcup, ti
+        enter_delete_mode,          // enter_delete_mode, smdc, dm
+        enter_dim_mode,             // enter_dim_mode, dim, mh
+        enter_doublewide_mode,      // enter_doublewide_mode, swidm, ZF
+        enter_draft_quality,        // enter_draft_quality, sdrfq, ZG
+        enter_insert_mode,          // enter_insert_mode, smir, im
+        enter_italics_mode,         // enter_italics_mode, sitm, ZH
+        enter_leftward_mode,        // enter_leftward_mode, slm, ZI
+        enter_micro_mode,           // enter_micro_mode, smicm, ZJ
+        enter_near_letter_quality,  // enter_near_letter_quality, snlq, ZK
+        enter_normal_quality,       // enter_normal_quality, snrmq, ZL
+        enter_protected_mode,       // enter_protected_mode, prot, mp
+        enter_reverse_mode,         // enter_reverse_mode, rev, mr
+        enter_secure_mode,          // enter_secure_mode, invis, mk
+        enter_shadow_mode,          // enter_shadow_mode, sshm, ZM
+        enter_standout_mode,        // enter_standout_mode, smso, so
+        enter_subscript_mode,       // enter_subscript_mode, ssubm, ZN
+        enter_superscript_mode,     // enter_superscript_mode, ssupm, ZO
+        enter_underline_mode,       // enter_underline_mode, smul, us
+        enter_upward_mode,          // enter_upward_mode, sum, ZP
+        enter_xon_mode,             // enter_xon_mode, smxon, SX
+        erase_chars,                // erase_chars, ech, ec
+        exit_alt_charset_mode,      // exit_alt_charset_mode, rmacs, ae
+        exit_am_mode,               // exit_am_mode, rmam, RA
+        exit_attribute_mode,        // exit_attribute_mode, sgr0, me
+        exit_ca_mode,               // exit_ca_mode, rmcup, te
+        exit_delete_mode,           // exit_delete_mode, rmdc, ed
+        exit_doublewide_mode,       // exit_doublewide_mode, rwidm, ZQ
+        exit_insert_mode,           // exit_insert_mode, rmir, ei
+        exit_italics_mode,          // exit_italics_mode, ritm, ZR
+        exit_leftward_mode,         // exit_leftward_mode, rlm, ZS
+        exit_micro_mode,            // exit_micro_mode, rmicm, ZT
+        exit_shadow_mode,           // exit_shadow_mode, rshm, ZU
+        exit_standout_mode,         // exit_standout_mode, rmso, se
+        exit_subscript_mode,        // exit_subscript_mode, rsubm, ZV
+        exit_superscript_mode,      // exit_superscript_mode, rsupm, ZW
+        exit_underline_mode,        // exit_underline_mode, rmul, ue
+        exit_upward_mode,           // exit_upward_mode, rum, ZX
+        exit_xon_mode,              // exit_xon_mode, rmxon, RX
+        fixed_pause,                // fixed_pause, pause, PA
+        flash_hook,                 // flash_hook, hook, fh
+        flash_screen,               // flash_screen, flash, vb
+        form_feed,                  // form_feed, ff, ff
+        from_status_line,           // from_status_line, fsl, fs
+        goto_window,                // goto_window, wingo, WG
+        hangup,                     // hangup, hup, HU
+        init_1string,               // init_1string, is1, i1
+        init_2string,               // init_2string, is2, is
+        init_3string,               // init_3string, is3, i3
+        init_file,                  // init_file, if, if
+        init_prog,                  // init_prog, iprog, iP
+        initialize_color,           // initialize_color, initc, Ic
+        initialize_pair,            // initialize_pair, initp, Ip
+        insert_character,           // insert_character, ich1, ic
+        insert_line,                // insert_line, il1, al
+        insert_padding,             // insert_padding, ip, ip
+        key_a1,                     // key_a1, ka1, K1
+        key_a3,                     // key_a3, ka3, K3
+        key_b2,                     // key_b2, kb2, K2
+        key_backspace,              // key_backspace, kbs, kb
+        key_beg,                    // key_beg, kbeg, @1
+        key_btab,                   // key_btab, kcbt, kB
+        key_c1,                     // key_c1, kc1, K4
+        key_c3,                     // key_c3, kc3, K5
+        key_cancel,                 // key_cancel, kcan, @2
+        key_catab,                  // key_catab, ktbc, ka
+        key_clear,                  // key_clear, kclr, kC
+        key_close,                  // key_close, kclo, @3
+        key_command,                // key_command, kcmd, @4
+        key_copy,                   // key_copy, kcpy, @5
+        key_create,                 // key_create, kcrt, @6
+        key_ctab,                   // key_ctab, kctab, kt
+        key_dc,                     // key_dc, kdch1, kD
+        key_dl,                     // key_dl, kdl1, kL
+        key_down,                   // key_down, kcud1, kd
+        key_eic,                    // key_eic, krmir, kM
+        key_end,                    // key_end, kend, @7
+        key_enter,                  // key_enter, kent, @8
+        key_eol,                    // key_eol, kel, kE
+        key_eos,                    // key_eos, ked, kS
+        key_exit,                   // key_exit, kext, @9
+        key_f0,                     // key_f0, kf0, k0
+        key_f1,                     // key_f1, kf1, k1
+        key_f10,                    // key_f10, kf10, k;
+        key_f11,                    // key_f11, kf11, F1
+        key_f12,                    // key_f12, kf12, F2
+        key_f13,                    // key_f13, kf13, F3
+        key_f14,                    // key_f14, kf14, F4
+        key_f15,                    // key_f15, kf15, F5
+        key_f16,                    // key_f16, kf16, F6
+        key_f17,                    // key_f17, kf17, F7
+        key_f18,                    // key_f18, kf18, F8
+        key_f19,                    // key_f19, kf19, F9
+        key_f2,                     // key_f2, kf2, k2
+        key_f20,                    // key_f20, kf20, FA
+        key_f21,                    // key_f21, kf21, FB
+        key_f22,                    // key_f22, kf22, FC
+        key_f23,                    // key_f23, kf23, FD
+        key_f24,                    // key_f24, kf24, FE
+        key_f25,                    // key_f25, kf25, FF
+        key_f26,                    // key_f26, kf26, FG
+        key_f27,                    // key_f27, kf27, FH
+        key_f28,                    // key_f28, kf28, FI
+        key_f29,                    // key_f29, kf29, FJ
+        key_f3,                     // key_f3, kf3, k3
+        key_f30,                    // key_f30, kf30, FK
+        key_f31,                    // key_f31, kf31, FL
+        key_f32,                    // key_f32, kf32, FM
+        key_f33,                    // key_f33, kf33, FN
+        key_f34,                    // key_f34, kf34, FO
+        key_f35,                    // key_f35, kf35, FP
+        key_f36,                    // key_f36, kf36, FQ
+        key_f37,                    // key_f37, kf37, FR
+        key_f38,                    // key_f38, kf38, FS
+        key_f39,                    // key_f39, kf39, FT
+        key_f4,                     // key_f4, kf4, k4
+        key_f40,                    // key_f40, kf40, FU
+        key_f41,                    // key_f41, kf41, FV
+        key_f42,                    // key_f42, kf42, FW
+        key_f43,                    // key_f43, kf43, FX
+        key_f44,                    // key_f44, kf44, FY
+        key_f45,                    // key_f45, kf45, FZ
+        key_f46,                    // key_f46, kf46, Fa
+        key_f47,                    // key_f47, kf47, Fb
+        key_f48,                    // key_f48, kf48, Fc
+        key_f49,                    // key_f49, kf49, Fd
+        key_f5,                     // key_f5, kf5, k5
+        key_f50,                    // key_f50, kf50, Fe
+        key_f51,                    // key_f51, kf51, Ff
+        key_f52,                    // key_f52, kf52, Fg
+        key_f53,                    // key_f53, kf53, Fh
+        key_f54,                    // key_f54, kf54, Fi
+        key_f55,                    // key_f55, kf55, Fj
+        key_f56,                    // key_f56, kf56, Fk
+        key_f57,                    // key_f57, kf57, Fl
+        key_f58,                    // key_f58, kf58, Fm
+        key_f59,                    // key_f59, kf59, Fn
+        key_f6,                     // key_f6, kf6, k6
+        key_f60,                    // key_f60, kf60, Fo
+        key_f61,                    // key_f61, kf61, Fp
+        key_f62,                    // key_f62, kf62, Fq
+        key_f63,                    // key_f63, kf63, Fr
+        key_f7,                     // key_f7, kf7, k7
+        key_f8,                     // key_f8, kf8, k8
+        key_f9,                     // key_f9, kf9, k9
+        key_find,                   // key_find, kfnd, @0
+        key_help,                   // key_help, khlp, %1
+        key_home,                   // key_home, khome, kh
+        key_ic,                     // key_ic, kich1, kI
+        key_il,                     // key_il, kil1, kA
+        key_left,                   // key_left, kcub1, kl
+        key_ll,                     // key_ll, kll, kH
+        key_mark,                   // key_mark, kmrk, %2
+        key_message,                // key_message, kmsg, %3
+        key_move,                   // key_move, kmov, %4
+        key_next,                   // key_next, knxt, %5
+        key_npage,                  // key_npage, knp, kN
+        key_open,                   // key_open, kopn, %6
+        key_options,                // key_options, kopt, %7
+        key_ppage,                  // key_ppage, kpp, kP
+        key_previous,               // key_previous, kprv, %8
+        key_print,                  // key_print, kprt, %9
+        key_redo,                   // key_redo, krdo, %0
+        key_reference,              // key_reference, kref, &1
+        key_refresh,                // key_refresh, krfr, &2
+        key_replace,                // key_replace, krpl, &3
+        key_restart,                // key_restart, krst, &4
+        key_resume,                 // key_resume, kres, &5
+        key_right,                  // key_right, kcuf1, kr
+        key_save,                   // key_save, ksav, &6
+        key_sbeg,                   // key_sbeg, kBEG, &9
+        key_scancel,                // key_scancel, kCAN, &0
+        key_scommand,               // key_scommand, kCMD, *1
+        key_scopy,                  // key_scopy, kCPY, *2
+        key_screate,                // key_screate, kCRT, *3
+        key_sdc,                    // key_sdc, kDC, *4
+        key_sdl,                    // key_sdl, kDL, *5
+        key_select,                 // key_select, kslt, *6
+        key_send,                   // key_send, kEND, *7
+        key_seol,                   // key_seol, kEOL, *8
+        key_sexit,                  // key_sexit, kEXT, *9
+        key_sf,                     // key_sf, kind, kF
+        key_sfind,                  // key_sfind, kFND, *0
+        key_shelp,                  // key_shelp, kHLP, #1
+        key_shome,                  // key_shome, kHOM, #2
+        key_sic,                    // key_sic, kIC, #3
+        key_sleft,                  // key_sleft, kLFT, #4
+        key_smessage,               // key_smessage, kMSG, %a
+        key_smove,                  // key_smove, kMOV, %b
+        key_snext,                  // key_snext, kNXT, %c
+        key_soptions,               // key_soptions, kOPT, %d
+        key_sprevious,              // key_sprevious, kPRV, %e
+        key_sprint,                 // key_sprint, kPRT, %f
+        key_sr,                     // key_sr, kri, kR
+        key_sredo,                  // key_sredo, kRDO, %g
+        key_sreplace,               // key_sreplace, kRPL, %h
+        key_sright,                 // key_sright, kRIT, %i
+        key_srsume,                 // key_srsume, kRES, %j
+        key_ssave,                  // key_ssave, kSAV, !1
+        key_ssuspend,               // key_ssuspend, kSPD, !2
+        key_stab,                   // key_stab, khts, kT
+        key_sundo,                  // key_sundo, kUND, !3
+        key_suspend,                // key_suspend, kspd, &7
+        key_undo,                   // key_undo, kund, &8
+        key_up,                     // key_up, kcuu1, ku
+        keypad_local,               // keypad_local, rmkx, ke
+        keypad_xmit,                // keypad_xmit, smkx, ks
+        lab_f0,                     // lab_f0, lf0, l0
+        lab_f1,                     // lab_f1, lf1, l1
+        lab_f10,                    // lab_f10, lf10, la
+        lab_f2,                     // lab_f2, lf2, l2
+        lab_f3,                     // lab_f3, lf3, l3
+        lab_f4,                     // lab_f4, lf4, l4
+        lab_f5,                     // lab_f5, lf5, l5
+        lab_f6,                     // lab_f6, lf6, l6
+        lab_f7,                     // lab_f7, lf7, l7
+        lab_f8,                     // lab_f8, lf8, l8
+        lab_f9,                     // lab_f9, lf9, l9
+        label_format,               // label_format, fln, Lf
+        label_off,                  // label_off, rmln, LF
+        label_on,                   // label_on, smln, LO
+        meta_off,                   // meta_off, rmm, mo
+        meta_on,                    // meta_on, smm, mm
+        micro_column_address,       // micro_column_address, mhpa, ZY
+        micro_down,                 // micro_down, mcud1, ZZ
+        micro_left,                 // micro_left, mcub1, Za
+        micro_right,                // micro_right, mcuf1, Zb
+        micro_row_address,          // micro_row_address, mvpa, Zc
+        micro_up,                   // micro_up, mcuu1, Zd
+        newline,                    // newline, nel, nw
+        order_of_pins,              // order_of_pins, porder, Ze
+        orig_colors,                // orig_colors, oc, oc
+        orig_pair,                  // orig_pair, op, op
+        pad_char,                   // pad_char, pad, pc
+        parm_dch,                   // parm_dch, dch, DC
+        parm_delete_line,           // parm_delete_line, dl, DL
+        parm_down_cursor,           // parm_down_cursor, cud, DO
+        parm_down_micro,            // parm_down_micro, mcud, Zf
+        parm_ich,                   // parm_ich, ich, IC
+        parm_index,                 // parm_index, indn, SF
+        parm_insert_line,           // parm_insert_line, il, AL
+        parm_left_cursor,           // parm_left_cursor, cub, LE
+        parm_left_micro,            // parm_left_micro, mcub, Zg
+        parm_right_cursor,          // parm_right_cursor, cuf, RI
+        parm_right_micro,           // parm_right_micro, mcuf, Zh
+        parm_rindex,                // parm_rindex, rin, SR
+        parm_up_cursor,             // parm_up_cursor, cuu, UP
+        parm_up_micro,              // parm_up_micro, mcuu, Zi
+        pkey_key,                   // pkey_key, pfkey, pk
+        pkey_local,                 // pkey_local, pfloc, pl
+        pkey_xmit,                  // pkey_xmit, pfx, px
+        plab_norm,                  // plab_norm, pln, pn
+        print_screen,               // print_screen, mc0, ps
+        prtr_non,                   // prtr_non, mc5p, pO
+        prtr_off,                   // prtr_off, mc4, pf
+        prtr_on,                    // prtr_on, mc5, po
+        pulse,                      // pulse, pulse, PU
+        quick_dial,                 // quick_dial, qdial, QD
+        remove_clock,               // remove_clock, rmclk, RC
+        repeat_char,                // repeat_char, rep, rp
+        req_for_input,              // req_for_input, rfi, RF
+        reset_1string,              // reset_1string, rs1, r1
+        reset_2string,              // reset_2string, rs2, r2
+        reset_3string,              // reset_3string, rs3, r3
+        reset_file,                 // reset_file, rf, rf
+        restore_cursor,             // restore_cursor, rc, rc
+        row_address,                // row_address, vpa, cv
+        save_cursor,                // save_cursor, sc, sc
+        scroll_forward,             // scroll_forward, ind, sf
+        scroll_reverse,             // scroll_reverse, ri, sr
+        select_char_set,            // select_char_set, scs, Zj
+        set_attributes,             // set_attributes, sgr, sa
+        set_background,             // set_background, setb, Sb
+        set_bottom_margin,          // set_bottom_margin, smgb, Zk
+        set_bottom_margin_parm,     // set_bottom_margin_parm, smgbp, Zl
+        set_clock,                  // set_clock, sclk, SC
+        set_color_pair,             // set_color_pair, scp, sp
+        set_foreground,             // set_foreground, setf, Sf
+        set_left_margin,            // set_left_margin, smgl, ML
+        set_left_margin_parm,       // set_left_margin_parm, smglp, Zm
+        set_right_margin,           // set_right_margin, smgr, MR
+        set_right_margin_parm,      // set_right_margin_parm, smgrp, Zn
+        set_tab,                    // set_tab, hts, st
+        set_top_margin,             // set_top_margin, smgt, Zo
+        set_top_margin_parm,        // set_top_margin_parm, smgtp, Zp
+        set_window,                 // set_window, wind, wi
+        start_bit_image,            // start_bit_image, sbim, Zq
+        start_char_set_def,         // start_char_set_def, scsd, Zr
+        stop_bit_image,             // stop_bit_image, rbim, Zs
+        stop_char_set_def,          // stop_char_set_def, rcsd, Zt
+        subscript_characters,       // subscript_characters, subcs, Zu
+        superscript_characters,     // superscript_characters, supcs, Zv
+        tab,                        // tab, ht, ta
+        these_cause_cr,             // these_cause_cr, docr, Zw
+        to_status_line,             // to_status_line, tsl, ts
+        tone,                       // tone, tone, TO
+        underline_char,             // underline_char, uc, uc
+        up_half_line,               // up_half_line, hu, hu
+        user0,                      // user0, u0, u0
+        user1,                      // user1, u1, u1
+        user2,                      // user2, u2, u2
+        user3,                      // user3, u3, u3
+        user4,                      // user4, u4, u4
+        user5,                      // user5, u5, u5
+        user6,                      // user6, u6, u6
+        user7,                      // user7, u7, u7
+        user8,                      // user8, u8, u8
+        user9,                      // user9, u9, u9
+        wait_tone,                  // wait_tone, wait, WA
+        xoff_character,             // xoff_character, xoffc, XF
+        xon_character,              // xon_character, xonc, XN
+        zero_motion,                // zero_motion, zerom, Zx
+        alt_scancode_esc,           // alt_scancode_esc, scesa, S8
+        bit_image_carriage_return,  // bit_image_carriage_return, bicr, Yv
+        bit_image_newline,          // bit_image_newline, binel, Zz
+        bit_image_repeat,           // bit_image_repeat, birep, Xy
+        char_set_names,             // char_set_names, csnm, Zy
+        code_set_init,              // code_set_init, csin, ci
+        color_names,                // color_names, colornm, Yw
+        define_bit_image_region,    // define_bit_image_region, defbi, Yx
+        device_type,                // device_type, devt, dv
+        display_pc_char,            // display_pc_char, dispc, S1
+        end_bit_image_region,       // end_bit_image_region, endbi, Yy
+        enter_pc_charset_mode,      // enter_pc_charset_mode, smpch, S2
+        enter_scancode_mode,        // enter_scancode_mode, smsc, S4
+        exit_pc_charset_mode,       // exit_pc_charset_mode, rmpch, S3
+        exit_scancode_mode,         // exit_scancode_mode, rmsc, S5
+        get_mouse,                  // get_mouse, getm, Gm
+        key_mouse,                  // key_mouse, kmous, Km
+        mouse_info,                 // mouse_info, minfo, Mi
+        pc_term_options,            // pc_term_options, pctrm, S6
+        pkey_plab,                  // pkey_plab, pfxl, xl
+        req_mouse_pos,              // req_mouse_pos, reqmp, RQ
+        scancode_escape,            // scancode_escape, scesc, S7
+        set0_des_seq,               // set0_des_seq, s0ds, s0
+        set1_des_seq,               // set1_des_seq, s1ds, s1
+        set2_des_seq,               // set2_des_seq, s2ds, s2
+        set3_des_seq,               // set3_des_seq, s3ds, s3
+        set_a_background,           // set_a_background, setab, AB
+        set_a_foreground,           // set_a_foreground, setaf, AF
+        set_color_band,             // set_color_band, setcolor, Yz
+        set_lr_margin,              // set_lr_margin, smglr, ML
+        set_page_length,            // set_page_length, slines, YZ
+        set_tb_margin,              // set_tb_margin, smgtb, MT
+        enter_horizontal_hl_mode,   // enter_horizontal_hl_mode, ehhlm, Xh
+        enter_left_hl_mode,         // enter_left_hl_mode, elhlm, Xl
+        enter_low_hl_mode,          // enter_low_hl_mode, elohlm, Xo
+        enter_right_hl_mode,        // enter_right_hl_mode, erhlm, Xr
+        enter_top_hl_mode,          // enter_top_hl_mode, ethlm, Xt
+        enter_vertical_hl_mode,     // enter_vertical_hl_mode, evhlm, Xv
+        set_a_attributes,           // set_a_attributes, sgr1, sA
+        set_pglen_inch,             // set_pglen_inch, slength, sL)
+        ;
+
+        public String[] getNames() {
+            return getCapabilitiesByName().entrySet().stream()
+                    .filter(e -> e.getValue() == this)
+                    .map(Map.Entry::getValue)
+                    .toArray(String[]::new);
+        }
+
+        public static Capability byName(String name) {
+            return getCapabilitiesByName().get(name);
+        }
+    }
+
+    public static Map<String, Capability> getCapabilitiesByName() {
+        Map<String, Capability> capabilities = new LinkedHashMap<>();
+        try (InputStream is = InfoCmp.class.getResourceAsStream("capabilities.txt");
+             BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+            br.lines().map(String::trim)
+                    .filter(s -> !s.startsWith("#"))
+                    .filter(s -> !s.isEmpty())
+                    .forEach(s -> {
+                        String[] names = s.split(", ");
+                        Capability cap = Enum.valueOf(Capability.class, names[0]);
+                        capabilities.put(names[0], cap);
+                        capabilities.put(names[1], cap);
+                    });
+            return capabilities;
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    public static void setDefaultInfoCmp(String terminal, String caps) {
+        CAPS.putIfAbsent(terminal, caps);
+    }
+
+    public static void setDefaultInfoCmp(String terminal, Supplier<String> caps) {
+        CAPS.putIfAbsent(terminal, caps);
+    }
+
+    public static String getInfoCmp(
+            String terminal
+    ) throws IOException, InterruptedException {
+        String caps = getLoadedInfoCmp(terminal);
+        if (caps == null) {
+            Process p = new ProcessBuilder(OSUtils.INFOCMP_COMMAND, terminal).start();
+            caps = ExecHelper.waitAndCapture(p);
+            CAPS.put(terminal, caps);
+        }
+        return caps;
+    }
+
+    public static String getLoadedInfoCmp(String terminal) {
+        Object caps = CAPS.get(terminal);
+        if (caps instanceof Supplier) {
+            caps = ((Supplier) caps).get();
+        }
+        return (String) caps;
+    }
+
+    public static void parseInfoCmp(
+            String capabilities,
+            Set<Capability> bools,
+            Map<Capability, Integer> ints,
+            Map<Capability, String> strings
+    ) {
+        Map<String, Capability> capsByName = getCapabilitiesByName();
+        String[] lines = capabilities.split("\n");
+        for (int i = 1; i < lines.length; i++) {
+            Matcher m = Pattern.compile("\\s*(([^,]|\\\\,)+)\\s*[,$]").matcher(lines[i]);
+            while (m.find()) {
+                String cap = m.group(1);
+                if (cap.contains("#")) {
+                    int index = cap.indexOf('#');
+                    String key = cap.substring(0, index);
+                    String val = cap.substring(index + 1);
+                    int iVal;
+                    if (val.startsWith("0x")) {
+                        iVal = Integer.parseInt(val.substring(2), 16);
+                    } else {
+                        iVal = Integer.parseInt(val);
+                    }
+                    Capability c = capsByName.get(key);
+                    if (c != null) {
+                        ints.put(c, iVal);
+                    }
+                } else if (cap.contains("=")) {
+                    int index = cap.indexOf('=');
+                    String key = cap.substring(0, index);
+                    String val = cap.substring(index + 1);
+                    Capability c = capsByName.get(key);
+                    if (c != null) {
+                        strings.put(c, val);
+                    }
+                } else {
+                    Capability c = capsByName.get(cap);
+                    if (c != null) {
+                        bools.add(c);
+                    }
+                }
+            }
+        }
+    }
+
+    static String loadDefaultInfoCmp(String name) {
+        try (InputStream is = InfoCmp.class.getResourceAsStream(name + ".caps");
+             BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+            return br.lines().collect(Collectors.joining("\n", "", "\n"));
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    static {
+        for (String s : Arrays.asList("dumb", "ansi", "xterm", "xterm-256color",
+                                      "windows", "windows-256color", "windows-vtp",
+                                      "screen", "screen-256color")) {
+            setDefaultInfoCmp(s, () -> loadDefaultInfoCmp(s));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InputStreamReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,346 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.UnmappableCharacterException;
+
+
+/**
+ *
+ * NOTE for JLine: the default InputStreamReader that comes from the JRE
+ * usually read more bytes than needed from the input stream, which
+ * is not usable in a character per character model used in the terminal.
+ * We thus use the harmony code which only reads the minimal number of bytes.
+ */
+
+/**
+ * A class for turning a byte stream into a character stream. Data read from the
+ * source input stream is converted into characters by either a default or a
+ * provided character converter. The default encoding is taken from the
+ * "file.encoding" system property. {@code InputStreamReader} contains a buffer
+ * of bytes read from the source stream and converts these into characters as
+ * needed. The buffer size is 8K.
+ *
+ * @see OutputStreamWriter
+ */
+public class InputStreamReader extends Reader {
+    private InputStream in;
+
+    private static final int BUFFER_SIZE = 4;
+
+    private boolean endOfInput = false;
+
+    CharsetDecoder decoder;
+
+    ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
+
+    char pending = (char) -1;
+
+    /**
+     * Constructs a new {@code InputStreamReader} on the {@link InputStream}
+     * {@code in}. This constructor sets the character converter to the encoding
+     * specified in the "file.encoding" property and falls back to ISO 8859_1
+     * (ISO-Latin-1) if the property doesn't exist.
+     *
+     * @param in
+     *            the input stream from which to read characters.
+     */
+    public InputStreamReader(InputStream in) {
+        super(in);
+        this.in = in;
+        decoder = Charset.defaultCharset().newDecoder().onMalformedInput(
+                CodingErrorAction.REPLACE).onUnmappableCharacter(
+                CodingErrorAction.REPLACE);
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in}. The
+     * character converter that is used to decode bytes into characters is
+     * identified by name by {@code enc}. If the encoding cannot be found, an
+     * UnsupportedEncodingException error is thrown.
+     *
+     * @param in
+     *            the InputStream from which to read characters.
+     * @param enc
+     *            identifies the character converter to use.
+     * @throws NullPointerException
+     *             if {@code enc} is {@code null}.
+     * @throws UnsupportedEncodingException
+     *             if the encoding specified by {@code enc} cannot be found.
+     */
+    public InputStreamReader(InputStream in, final String enc)
+            throws UnsupportedEncodingException {
+        super(in);
+        if (enc == null) {
+            throw new NullPointerException();
+        }
+        this.in = in;
+        try {
+            decoder = Charset.forName(enc).newDecoder().onMalformedInput(
+                    CodingErrorAction.REPLACE).onUnmappableCharacter(
+                    CodingErrorAction.REPLACE);
+        } catch (IllegalArgumentException e) {
+            throw (UnsupportedEncodingException)
+                    new UnsupportedEncodingException(enc).initCause(e);
+        }
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in} and
+     * CharsetDecoder {@code dec}.
+     *
+     * @param in
+     *            the source InputStream from which to read characters.
+     * @param dec
+     *            the CharsetDecoder used by the character conversion.
+     */
+    public InputStreamReader(InputStream in, CharsetDecoder dec) {
+        super(in);
+        dec.averageCharsPerByte();
+        this.in = in;
+        decoder = dec;
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in} and
+     * Charset {@code charset}.
+     *
+     * @param in
+     *            the source InputStream from which to read characters.
+     * @param charset
+     *            the Charset that defines the character converter
+     */
+    public InputStreamReader(InputStream in, Charset charset) {
+        super(in);
+        this.in = in;
+        decoder = charset.newDecoder().onMalformedInput(
+                CodingErrorAction.REPLACE).onUnmappableCharacter(
+                CodingErrorAction.REPLACE);
+        bytes.limit(0);
+    }
+
+    /**
+     * Closes this reader. This implementation closes the source InputStream and
+     * releases all local storage.
+     *
+     * @throws IOException
+     *             if an error occurs attempting to close this reader.
+     */
+    @Override
+    public void close() throws IOException {
+        synchronized (lock) {
+            decoder = null;
+            if (in != null) {
+                in.close();
+                in = null;
+            }
+        }
+    }
+
+    /**
+     * Returns the name of the encoding used to convert bytes into characters.
+     * The value {@code null} is returned if this reader has been closed.
+     *
+     * @return the name of the character converter or {@code null} if this
+     *         reader is closed.
+     */
+    public String getEncoding() {
+        if (!isOpen()) {
+            return null;
+        }
+        return decoder.charset().name();
+    }
+
+    /**
+     * Reads a single character from this reader and returns it as an integer
+     * with the two higher-order bytes set to 0. Returns -1 if the end of the
+     * reader has been reached. The byte value is either obtained from
+     * converting bytes in this reader's buffer or by first filling the buffer
+     * from the source InputStream and then reading from the buffer.
+     *
+     * @return the character read or -1 if the end of the reader has been
+     *         reached.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public int read() throws IOException {
+        synchronized (lock) {
+            if (!isOpen()) {
+                throw new ClosedException("InputStreamReader is closed.");
+            }
+
+            if (pending != (char) -1) {
+                char c = pending;
+                pending = (char) -1;
+                return c;
+            }
+            char buf[] = new char[2];
+            int nb = read(buf, 0, 2);
+            if (nb == 2) {
+                pending = buf[1];
+            }
+            if (nb > 0) {
+                return buf[0];
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    /**
+     * Reads at most {@code length} characters from this reader and stores them
+     * at position {@code offset} in the character array {@code buf}. Returns
+     * the number of characters actually read or -1 if the end of the reader has
+     * been reached. The bytes are either obtained from converting bytes in this
+     * reader's buffer or by first filling the buffer from the source
+     * InputStream and then reading from the buffer.
+     *
+     * @param buf
+     *            the array to store the characters read.
+     * @param offset
+     *            the initial position in {@code buf} to store the characters
+     *            read from this reader.
+     * @param length
+     *            the maximum number of characters to read.
+     * @return the number of characters read or -1 if the end of the reader has
+     *         been reached.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0} or {@code length < 0}, or if
+     *             {@code offset + length} is greater than the length of
+     *             {@code buf}.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public int read(char[] buf, int offset, int length) throws IOException {
+        synchronized (lock) {
+            if (!isOpen()) {
+                throw new IOException("InputStreamReader is closed.");
+            }
+            if (offset < 0 || offset > buf.length - length || length < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (length == 0) {
+                return 0;
+            }
+
+            CharBuffer out = CharBuffer.wrap(buf, offset, length);
+            CoderResult result = CoderResult.UNDERFLOW;
+
+            // bytes.remaining() indicates number of bytes in buffer
+            // when 1-st time entered, it'll be equal to zero
+            boolean needInput = !bytes.hasRemaining();
+
+            while (out.position() == offset) {
+                // fill the buffer if needed
+                if (needInput) {
+                    try {
+                        if ((in.available() == 0)
+                            && (out.position() > offset)) {
+                            // we could return the result without blocking read
+                            break;
+                        }
+                    } catch (IOException e) {
+                        // available didn't work so just try the read
+                    }
+
+                    int off = bytes.arrayOffset() + bytes.limit();
+                    int was_red = in.read(bytes.array(), off, 1);
+
+                    if (was_red == -1) {
+                        endOfInput = true;
+                        break;
+                    } else if (was_red == 0) {
+                        break;
+                    }
+                    bytes.limit(bytes.limit() + was_red);
+                }
+
+                // decode bytes
+                result = decoder.decode(bytes, out, false);
+
+                if (result.isUnderflow()) {
+                    // compact the buffer if no space left
+                    if (bytes.limit() == bytes.capacity()) {
+                        bytes.compact();
+                        bytes.limit(bytes.position());
+                        bytes.position(0);
+                    }
+                    needInput = true;
+                } else {
+                    break;
+                }
+            }
+
+            if (result == CoderResult.UNDERFLOW && endOfInput) {
+                result = decoder.decode(bytes, out, true);
+                decoder.flush(out);
+                decoder.reset();
+            }
+            if (result.isMalformed()) {
+                throw new MalformedInputException(result.length());
+            } else if (result.isUnmappable()) {
+                throw new UnmappableCharacterException(result.length());
+            }
+
+            return out.position() - offset == 0 ? -1 : out.position() - offset;
+        }
+    }
+
+    /*
+     * Answer a boolean indicating whether or not this InputStreamReader is
+     * open.
+     */
+    private boolean isOpen() {
+        return in != null;
+    }
+
+    /**
+     * Indicates whether this reader is ready to be read without blocking. If
+     * the result is {@code true}, the next {@code read()} will not block. If
+     * the result is {@code false} then this reader may or may not block when
+     * {@code read()} is called. This implementation returns {@code true} if
+     * there are bytes available in the buffer or the source stream has bytes
+     * available.
+     *
+     * @return {@code true} if the receiver will not block when {@code read()}
+     *         is called, {@code false} if unknown or blocking will occur.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+            if (in == null) {
+                throw new IOException("InputStreamReader is closed.");
+            }
+            try {
+                return bytes.hasRemaining() || in.available() > 0;
+            } catch (IOException e) {
+                return false;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Levenshtein.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,119 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Damerau-Levenshtein Algorithm is an extension to the Levenshtein
+ * Algorithm which solves the edit distance problem between a source string and
+ * a target string with the following operations:
+ *
+ * <ul>
+ * <li>Character Insertion</li>
+ * <li>Character Deletion</li>
+ * <li>Character Replacement</li>
+ * <li>Adjacent Character Swap</li>
+ * </ul>
+ *
+ * Note that the adjacent character swap operation is an edit that may be
+ * applied when two adjacent characters in the source string match two adjacent
+ * characters in the target string, but in reverse order, rather than a general
+ * allowance for adjacent character swaps.
+ * <p>
+ *
+ * This implementation allows the client to specify the costs of the various
+ * edit operations with the restriction that the cost of two swap operations
+ * must not be less than the cost of a delete operation followed by an insert
+ * operation. This restriction is required to preclude two swaps involving the
+ * same character being required for optimality which, in turn, enables a fast
+ * dynamic programming solution.
+ * <p>
+ *
+ * The running time of the Damerau-Levenshtein algorithm is O(n*m) where n is
+ * the length of the source string and m is the length of the target string.
+ * This implementation consumes O(n*m) space.
+ *
+ * @author Kevin L. Stern
+ */
+public class Levenshtein {
+
+    public static int distance(CharSequence lhs, CharSequence rhs) {
+        return distance(lhs, rhs, 1, 1, 1, 1);
+    }
+
+    public static int distance(CharSequence source, CharSequence target,
+                               int deleteCost, int insertCost,
+                               int replaceCost, int swapCost) {
+        /*
+         * Required to facilitate the premise to the algorithm that two swaps of the
+         * same character are never required for optimality.
+         */
+        if (2 * swapCost < insertCost + deleteCost) {
+            throw new IllegalArgumentException("Unsupported cost assignment");
+        }
+        if (source.length() == 0) {
+            return target.length() * insertCost;
+        }
+        if (target.length() == 0) {
+            return source.length() * deleteCost;
+        }
+        int[][] table = new int[source.length()][target.length()];
+        Map<Character, Integer> sourceIndexByCharacter = new HashMap<>();
+        if (source.charAt(0) != target.charAt(0)) {
+            table[0][0] = Math.min(replaceCost, deleteCost + insertCost);
+        }
+        sourceIndexByCharacter.put(source.charAt(0), 0);
+        for (int i = 1; i < source.length(); i++) {
+            int deleteDistance = table[i - 1][0] + deleteCost;
+            int insertDistance = (i + 1) * deleteCost + insertCost;
+            int matchDistance = i * deleteCost + (source.charAt(i) == target.charAt(0) ? 0 : replaceCost);
+            table[i][0] = Math.min(Math.min(deleteDistance, insertDistance), matchDistance);
+        }
+        for (int j = 1; j < target.length(); j++) {
+            int deleteDistance = (j + 1) * insertCost + deleteCost;
+            int insertDistance = table[0][j - 1] + insertCost;
+            int matchDistance = j * insertCost + (source.charAt(0) == target.charAt(j) ? 0 : replaceCost);
+            table[0][j] = Math.min(Math.min(deleteDistance, insertDistance), matchDistance);
+        }
+        for (int i = 1; i < source.length(); i++) {
+            int maxSourceLetterMatchIndex = source.charAt(i) == target.charAt(0) ? 0 : -1;
+            for (int j = 1; j < target.length(); j++) {
+                Integer candidateSwapIndex = sourceIndexByCharacter.get(target.charAt(j));
+                int jSwap = maxSourceLetterMatchIndex;
+                int deleteDistance = table[i - 1][j] + deleteCost;
+                int insertDistance = table[i][j - 1] + insertCost;
+                int matchDistance = table[i - 1][j - 1];
+                if (source.charAt(i) != target.charAt(j)) {
+                    matchDistance += replaceCost;
+                } else {
+                    maxSourceLetterMatchIndex = j;
+                }
+                int swapDistance;
+                if (candidateSwapIndex != null && jSwap != -1) {
+                    int iSwap = candidateSwapIndex;
+                    int preSwapCost;
+                    if (iSwap == 0 && jSwap == 0) {
+                        preSwapCost = 0;
+                    } else {
+                        preSwapCost = table[Math.max(0, iSwap - 1)][Math.max(0, jSwap - 1)];
+                    }
+                    swapDistance = preSwapCost + (i - iSwap - 1) * deleteCost + (j - jSwap - 1) * insertCost + swapCost;
+                } else {
+                    swapDistance = Integer.MAX_VALUE;
+                }
+                table[i][j] = Math.min(Math.min(Math.min(deleteDistance, insertDistance), matchDistance), swapDistance);
+            }
+            sourceIndexByCharacter.put(source.charAt(i), i);
+        }
+        return table[source.length() - 1][target.length() - 1];
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.function.Supplier;
+//import java.util.logging.Level;
+//import java.util.logging.LogRecord;
+//import java.util.logging.Logger;
+
+/**
+ * Internal logger.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.0
+ */
+public final class Log
+{
+    public static void trace(final Object... messages) {
+//        log(Level.FINEST, messages);
+    }
+
+    public static void trace(Supplier<String> supplier) {
+//        log(Level.FINEST, supplier);
+    }
+
+    public static void debug(Supplier<String> supplier) {
+//        log(Level.FINE, supplier);
+    }
+
+    public static void debug(final Object... messages) {
+//        log(Level.FINE, messages);
+    }
+
+    public static void info(final Object... messages) {
+//        log(Level.INFO, messages);
+    }
+
+    public static void warn(final Object... messages) {
+//        log(Level.WARNING, messages);
+    }
+
+    public static void error(final Object... messages) {
+//        log(Level.SEVERE, messages);
+    }
+
+    public static boolean isDebugEnabled() {
+//        return isEnabled(Level.FINE);
+        return false;
+    }
+
+    /**
+     * Helper to support rendering messages.
+     */
+    static void render(final PrintStream out, final Object message) {
+        if (message != null && message.getClass().isArray()) {
+            Object[] array = (Object[]) message;
+
+            out.print("[");
+            for (int i = 0; i < array.length; i++) {
+                out.print(array[i]);
+                if (i + 1 < array.length) {
+                    out.print(",");
+                }
+            }
+            out.print("]");
+        }
+        else {
+            out.print(message);
+        }
+    }
+
+//    static LogRecord createRecord(final Level level, final Object... messages) {
+//        Throwable cause = null;
+//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+//        PrintStream ps = new PrintStream(baos);
+//        for (int i = 0; i < messages.length; i++) {
+//            // Special handling for the last message if its a throwable, render its stack on the next line
+//            if (i + 1 == messages.length && messages[i] instanceof Throwable) {
+//                cause = (Throwable) messages[i];
+//            }
+//            else {
+//                render(ps, messages[i]);
+//            }
+//        }
+//        ps.close();
+//        LogRecord r = new LogRecord(level, baos.toString());
+//        r.setThrown(cause);
+//        return r;
+//    }
+//
+//    static LogRecord createRecord(final Level level, final Supplier<String> message) {
+//        return new LogRecord(level, message.get());
+//    }
+//
+//    static void log(final Level level, final Supplier<String> message) {
+//        logr(level, () -> createRecord(level, message));
+//    }
+//
+//    static void log(final Level level, final Object... messages) {
+//        logr(level, () -> createRecord(level, messages));
+//    }
+//
+//    static void logr(final Level level, final Supplier<LogRecord> record) {
+//        Logger logger = Logger.getLogger("org.jline");
+//        if (logger.isLoggable(level)) {
+//            // inform record of the logger-name
+//            LogRecord tmp = record.get();
+//            tmp.setLoggerName(logger.getName());
+//            logger.log(tmp);
+//        }
+//    }
+//
+//    static boolean isEnabled(Level level) {
+//        Logger logger = Logger.getLogger("org.jline");
+//        return logger.isLoggable(level);
+//    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlocking.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+
+public class NonBlocking {
+
+    public static NonBlockingPumpReader nonBlockingPumpReader() {
+        return new NonBlockingPumpReader();
+    }
+
+    public static NonBlockingPumpReader nonBlockingPumpReader(int size) {
+        return new NonBlockingPumpReader(size);
+    }
+
+    public static NonBlockingPumpInputStream nonBlockingPumpInputStream() {
+        return new NonBlockingPumpInputStream();
+    }
+
+    public static NonBlockingPumpInputStream nonBlockingPumpInputStream(int size) {
+        return new NonBlockingPumpInputStream(size);
+    }
+
+    public static NonBlockingInputStream nonBlockingStream(NonBlockingReader reader, Charset encoding) {
+        return new NonBlockingReaderInputStream(reader, encoding);
+    }
+
+    public static NonBlockingInputStream nonBlocking(String name, InputStream inputStream) {
+        if (inputStream instanceof NonBlockingInputStream) {
+            return (NonBlockingInputStream) inputStream;
+        }
+        return new NonBlockingInputStreamImpl(name, inputStream);
+    }
+
+    public static NonBlockingReader nonBlocking(String name, Reader reader) {
+        if (reader instanceof NonBlockingReader) {
+            return (NonBlockingReader) reader;
+        }
+        return new NonBlockingReaderImpl(name, reader);
+    }
+
+    public static NonBlockingReader nonBlocking(String name, InputStream inputStream, Charset encoding) {
+        return new NonBlockingInputStreamReader(nonBlocking(name, inputStream), encoding);
+    }
+
+    private static class NonBlockingReaderInputStream extends NonBlockingInputStream {
+
+        private final NonBlockingReader reader;
+        private final CharsetEncoder encoder;
+
+        // To encode a character with multiple bytes (e.g. certain Unicode characters)
+        // we need enough space to encode them. Reading would fail if the read() method
+        // is used to read a single byte in these cases.
+        // Use this buffer to ensure we always have enough space to encode a character.
+        private final ByteBuffer bytes;
+        private final CharBuffer chars;
+
+        private NonBlockingReaderInputStream(NonBlockingReader reader, Charset charset) {
+            this.reader = reader;
+            this.encoder = charset.newEncoder()
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE)
+                    .onMalformedInput(CodingErrorAction.REPLACE);
+            this.bytes = ByteBuffer.allocate(4);
+            this.chars = CharBuffer.allocate(2);
+            // No input available after initialization
+            this.bytes.limit(0);
+            this.chars.limit(0);
+        }
+
+        @Override
+        public int available() {
+            return (int) (reader.available() * this.encoder.averageBytesPerChar())
+                    + bytes.remaining();
+        }
+
+        @Override
+        public void close() throws IOException {
+            reader.close();
+        }
+
+        @Override
+        public int read(long timeout, boolean isPeek) throws IOException {
+            boolean isInfinite = (timeout <= 0L);
+            while (!bytes.hasRemaining() && (isInfinite || timeout > 0L)) {
+                long start = 0;
+                if (!isInfinite) {
+                    start = System.currentTimeMillis();
+                }
+                int c = reader.read(timeout);
+                if (c == EOF) {
+                    return EOF;
+                }
+                if (c >= 0) {
+                    if (!chars.hasRemaining()) {
+                        chars.position(0);
+                        chars.limit(0);
+                    }
+                    int l = chars.limit();
+                    chars.array()[chars.arrayOffset() + l] = (char) c;
+                    chars.limit(l + 1);
+                    bytes.clear();
+                    encoder.encode(chars, bytes, false);
+                    bytes.flip();
+                }
+                if (!isInfinite) {
+                    timeout -= System.currentTimeMillis() - start;
+                }
+            }
+            if (bytes.hasRemaining()) {
+                if (isPeek) {
+                    return bytes.get(bytes.position());
+                } else {
+                    return bytes.get();
+                }
+            } else {
+                return READ_EXPIRED;
+            }
+        }
+
+    }
+
+    private static class NonBlockingInputStreamReader extends NonBlockingReader {
+
+        private final NonBlockingInputStream input;
+        private final CharsetDecoder decoder;
+        private final ByteBuffer bytes;
+        private final CharBuffer chars;
+
+        public NonBlockingInputStreamReader(NonBlockingInputStream inputStream, Charset encoding) {
+            this(inputStream,
+                (encoding != null ? encoding : Charset.defaultCharset()).newDecoder()
+                    .onMalformedInput(CodingErrorAction.REPLACE)
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE));
+        }
+
+        public NonBlockingInputStreamReader(NonBlockingInputStream input, CharsetDecoder decoder) {
+            this.input = input;
+            this.decoder = decoder;
+            this.bytes = ByteBuffer.allocate(4);
+            this.chars = CharBuffer.allocate(2);
+            this.bytes.limit(0);
+            this.chars.limit(0);
+        }
+
+        @Override
+        protected int read(long timeout, boolean isPeek) throws IOException {
+            boolean isInfinite = (timeout <= 0L);
+            while (!chars.hasRemaining() && (isInfinite || timeout > 0L)) {
+                long start = 0;
+                if (!isInfinite) {
+                    start = System.currentTimeMillis();
+                }
+                int b = input.read(timeout);
+                if (b == EOF) {
+                    return EOF;
+                }
+                if (b >= 0) {
+                    if (!bytes.hasRemaining()) {
+                        bytes.position(0);
+                        bytes.limit(0);
+                    }
+                    int l = bytes.limit();
+                    bytes.array()[bytes.arrayOffset() + l] = (byte) b;
+                    bytes.limit(l + 1);
+                    chars.clear();
+                    decoder.decode(bytes, chars, false);
+                    chars.flip();
+                }
+
+                if (!isInfinite) {
+                    timeout -= System.currentTimeMillis() - start;
+                }
+            }
+            if (chars.hasRemaining()) {
+                if (isPeek) {
+                    return chars.get(chars.position());
+                } else {
+                    return chars.get();
+                }
+            } else {
+                return READ_EXPIRED;
+            }
+        }
+
+        @Override
+        public void shutdown() {
+            input.shutdown();
+        }
+
+        @Override
+        public void close() throws IOException {
+            input.close();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStream.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Non blocking input stream
+ */
+public abstract class NonBlockingInputStream extends InputStream {
+
+    public static final int EOF = -1;
+    public static final int READ_EXPIRED = -2;
+
+    /**
+     * Reads the next byte of data from the input stream. The value byte is
+     * returned as an <code>int</code> in the range <code>0</code> to
+     * <code>255</code>. If no byte is available because the end of the stream
+     * has been reached, the value <code>-1</code> is returned. This method
+     * blocks until input data is available, the end of the stream is detected,
+     * or an exception is thrown.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    @Override
+    public int read() throws IOException {
+        return read(0L, false);
+    }
+
+    /**
+     * Peeks to see if there is a byte waiting in the input stream without
+     * actually consuming the byte.
+     *
+     * @param      timeout The amount of time to wait, 0 == forever
+     * @return     -1 on eof, -2 if the timeout expired with no available input
+     *             or the character that was read (without consuming it).
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int peek(long timeout) throws IOException {
+        return read(timeout, true);
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     *
+     * @param      timeout      The amount of time to wait for the character
+     * @return     The character read, -1 if EOF is reached,
+     *             or -2 if the read timed out.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read(long timeout) throws IOException {
+        return read(timeout, false);
+    }
+
+    public int read(byte b[], int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        int c = read();
+        if (c == EOF) {
+            return EOF;
+        }
+        b[off] = (byte)c;
+        return 1;
+    }
+
+    /**
+     * Shuts down the thread that is handling blocking I/O if any. Note that if the
+     * thread is currently blocked waiting for I/O it may not actually
+     * shut down until the I/O is received.
+     */
+    public void shutdown() {
+    }
+
+    public abstract int read(long timeout, boolean isPeek) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingInputStreamImpl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+/**
+ * This class wraps a regular input stream and allows it to appear as if it
+ * is non-blocking; that is, reads can be performed against it that timeout
+ * if no data is seen for a period of time.  This effect is achieved by having
+ * a separate thread perform all non-blocking read requests and then
+ * waiting on the thread to complete.
+ *
+ * <p>VERY IMPORTANT NOTES
+ * <ul>
+ *   <li> This class is not thread safe. It expects at most one reader.
+ *   <li> The {@link #shutdown()} method must be called in order to shut down
+ *          the thread that handles blocking I/O.
+ * </ul>
+ */
+public class NonBlockingInputStreamImpl
+    extends NonBlockingInputStream
+{
+    private InputStream in;                  // The actual input stream
+    private int         b = READ_EXPIRED;    // Recently read byte
+
+    private String      name;
+    private boolean     threadIsReading      = false;
+    private IOException exception            = null;
+    private long        threadDelay          = 60 * 1000;
+    private Thread      thread;
+
+    /**
+     * Creates a <code>NonBlockingReader</code> out of a normal blocking
+     * reader. Note that this call also spawn a separate thread to perform the
+     * blocking I/O on behalf of the thread that is using this class. The
+     * {@link #shutdown()} method must be called in order to shut this thread down.
+     * @param name The stream name
+     * @param in The reader to wrap
+     */
+    public NonBlockingInputStreamImpl(String name, InputStream in) {
+        this.in = in;
+        this.name = name;
+    }
+
+    private synchronized void startReadingThreadIfNeeded() {
+        if (thread == null) {
+            thread = new Thread(this::run);
+            thread.setName(name + " non blocking reader thread");
+            thread.setDaemon(true);
+            thread.start();
+        }
+    }
+
+    /**
+     * Shuts down the thread that is handling blocking I/O. Note that if the
+     * thread is currently blocked waiting for I/O it will not actually
+     * shut down until the I/O is received.
+     */
+    public synchronized void shutdown() {
+        if (thread != null) {
+            notify();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        /*
+         * The underlying input stream is closed first. This means that if the
+         * I/O thread was blocked waiting on input, it will be woken for us.
+         */
+        in.close();
+        shutdown();
+    }
+
+    /**
+     * Attempts to read a byte from the input stream for a specific
+     * period of time.
+     * @param timeout The amount of time to wait for the character
+     * @param isPeek <code>true</code>if the byte read must not be consumed
+     * @return The byte read, -1 if EOF is reached, or -2 if the
+     *   read timed out.
+     * @throws IOException if anything wrong happens
+     */
+    public synchronized int read(long timeout, boolean isPeek) throws IOException {
+        /*
+         * If the thread hit an IOException, we report it.
+         */
+        if (exception != null) {
+            assert b == READ_EXPIRED;
+            IOException toBeThrown = exception;
+            if (!isPeek)
+                exception = null;
+            throw toBeThrown;
+        }
+
+        /*
+         * If there was a pending character from the thread, then
+         * we send it. If the timeout is 0L or the thread was shut down
+         * then do a local read.
+         */
+        if (b >= -1) {
+            assert exception == null;
+        }
+        else if (!isPeek && timeout <= 0L && !threadIsReading) {
+            b = in.read();
+        }
+        else {
+            /*
+             * If the thread isn't reading already, then ask it to do so.
+             */
+            if (!threadIsReading) {
+                threadIsReading = true;
+                startReadingThreadIfNeeded();
+                notifyAll();
+            }
+
+            boolean isInfinite = (timeout <= 0L);
+
+            /*
+             * So the thread is currently doing the reading for us. So
+             * now we play the waiting game.
+             */
+            while (isInfinite || timeout > 0L)  {
+                long start = System.currentTimeMillis ();
+
+                try {
+                    if (Thread.interrupted()) {
+                        throw new InterruptedException();
+                    }
+                    wait(timeout);
+                }
+                catch (InterruptedException e) {
+                    exception = (IOException) new InterruptedIOException().initCause(e);
+                }
+
+                if (exception != null) {
+                    assert b == READ_EXPIRED;
+
+                    IOException toBeThrown = exception;
+                    if (!isPeek)
+                        exception = null;
+                    throw toBeThrown;
+                }
+
+                if (b >= -1) {
+                    assert exception == null;
+                    break;
+                }
+
+                if (!isInfinite) {
+                    timeout -= System.currentTimeMillis() - start;
+                }
+            }
+        }
+
+        /*
+         * b is the character that was just read. Either we set it because
+         * a local read was performed or the read thread set it (or failed to
+         * change it).  We will return it's value, but if this was a peek
+         * operation, then we leave it in place.
+         */
+        int ret = b;
+        if (!isPeek) {
+            b = READ_EXPIRED;
+        }
+        return ret;
+    }
+
+    private void run () {
+        Log.debug("NonBlockingInputStream start");
+        boolean needToRead;
+
+        try {
+            while (true) {
+
+                /*
+                 * Synchronize to grab variables accessed by both this thread
+                 * and the accessing thread.
+                 */
+                synchronized (this) {
+                    needToRead = this.threadIsReading;
+
+                    try {
+                        /*
+                         * Nothing to do? Then wait.
+                         */
+                        if (!needToRead) {
+                            wait(threadDelay);
+                        }
+                    } catch (InterruptedException e) {
+                        /* IGNORED */
+                    }
+
+                    needToRead = this.threadIsReading;
+                    if (!needToRead) {
+                        return;
+                    }
+                }
+
+                /*
+                 * We're not shutting down, but we need to read. This cannot
+                 * happen while we are holding the lock (which we aren't now).
+                 */
+                int byteRead = READ_EXPIRED;
+                IOException failure = null;
+                try {
+                    byteRead = in.read();
+                } catch (IOException e) {
+                    failure = e;
+                }
+
+                /*
+                 * Re-grab the lock to update the state.
+                 */
+                synchronized (this) {
+                    exception = failure;
+                    b = byteRead;
+                    threadIsReading = false;
+                    notify();
+                }
+
+                // If end of stream, exit the loop thread
+                if (byteRead < 0) {
+                    return;
+                }
+            }
+        } catch (Throwable t) {
+            Log.warn("Error in NonBlockingInputStream thread", t);
+        } finally {
+            Log.debug("NonBlockingInputStream shutdown");
+            synchronized (this) {
+                thread = null;
+                threadIsReading = false;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+public class NonBlockingPumpInputStream extends NonBlockingInputStream {
+
+    private static final int DEFAULT_BUFFER_SIZE = 4096;
+
+    // Read and write buffer are backed by the same array
+    private final ByteBuffer readBuffer;
+    private final ByteBuffer writeBuffer;
+
+    private final OutputStream output;
+
+    private boolean closed;
+
+    private IOException ioException;
+
+    public NonBlockingPumpInputStream() {
+        this(DEFAULT_BUFFER_SIZE);
+    }
+
+    public NonBlockingPumpInputStream(int bufferSize) {
+        byte[] buf = new byte[bufferSize];
+        this.readBuffer = ByteBuffer.wrap(buf);
+        this.writeBuffer = ByteBuffer.wrap(buf);
+        this.output = new NbpOutputStream();
+        // There are no bytes available to read after initialization
+        readBuffer.limit(0);
+    }
+
+    public OutputStream getOutputStream() {
+        return this.output;
+    }
+
+    private int wait(ByteBuffer buffer, long timeout) throws IOException {
+        boolean isInfinite = (timeout <= 0L);
+        long end = 0;
+        if (!isInfinite) {
+            end = System.currentTimeMillis() + timeout;
+        }
+        while (!closed && !buffer.hasRemaining() && (isInfinite || timeout > 0L)) {
+            // Wake up waiting readers/writers
+            notifyAll();
+            try {
+                wait(timeout);
+                checkIoException();
+            } catch (InterruptedException e) {
+                checkIoException();
+                throw new InterruptedIOException();
+            }
+            if (!isInfinite) {
+                timeout = end - System.currentTimeMillis();
+            }
+        }
+        return buffer.hasRemaining()
+                ? 0
+                : closed
+                    ? EOF
+                    : READ_EXPIRED;
+    }
+
+    private static boolean rewind(ByteBuffer buffer, ByteBuffer other) {
+        // Extend limit of other buffer if there is additional input/output available
+        if (buffer.position() > other.position()) {
+            other.limit(buffer.position());
+        }
+        // If we have reached the end of the buffer, rewind and set the new limit
+        if (buffer.position() == buffer.capacity()) {
+            buffer.rewind();
+            buffer.limit(other.position());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public synchronized int available() {
+        int count = readBuffer.remaining();
+        if (writeBuffer.position() < readBuffer.position()) {
+            count += writeBuffer.position();
+        }
+        return count;
+    }
+
+    @Override
+    public synchronized int read(long timeout, boolean isPeek) throws IOException {
+        checkIoException();
+        // Blocks until more input is available or the reader is closed.
+        int res = wait(readBuffer, timeout);
+        if (res >= 0) {
+            res = readBuffer.get() & 0x00FF;
+        }
+        rewind(readBuffer, writeBuffer);
+        return res;
+    }
+
+    public synchronized void setIoException(IOException exception) {
+        this.ioException = exception;
+        notifyAll();
+    }
+
+    protected synchronized void checkIoException() throws IOException {
+        if (ioException != null) {
+            throw ioException;
+        }
+    }
+
+    synchronized void write(byte[] cbuf, int off, int len) throws IOException {
+        while (len > 0) {
+            // Blocks until there is new space available for buffering or the
+            // reader is closed.
+            if (wait(writeBuffer, 0L) == EOF) {
+                throw new ClosedException();
+            }
+            // Copy as much characters as we can
+            int count = Math.min(len, writeBuffer.remaining());
+            writeBuffer.put(cbuf, off, count);
+            off += count;
+            len -= count;
+            // Update buffer states and rewind if necessary
+            rewind(writeBuffer, readBuffer);
+        }
+    }
+
+    synchronized void flush() {
+        // Avoid waking up readers when there is nothing to read
+        if (readBuffer.hasRemaining()) {
+            // Notify readers
+            notifyAll();
+        }
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        this.closed = true;
+        notifyAll();
+    }
+
+    private class NbpOutputStream extends OutputStream {
+
+        @Override
+        public void write(int b) throws IOException {
+            NonBlockingPumpInputStream.this.write(new byte[] { (byte) b }, 0, 1);
+        }
+
+        @Override
+        public void write(byte[] cbuf, int off, int len) throws IOException {
+            NonBlockingPumpInputStream.this.write(cbuf, off, len);
+        }
+
+        @Override
+        public void flush() throws IOException {
+            NonBlockingPumpInputStream.this.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            NonBlockingPumpInputStream.this.close();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Writer;
+import java.nio.CharBuffer;
+
+public class NonBlockingPumpReader extends NonBlockingReader {
+
+    private static final int DEFAULT_BUFFER_SIZE = 4096;
+
+    // Read and write buffer are backed by the same array
+    private final CharBuffer readBuffer;
+    private final CharBuffer writeBuffer;
+
+    private final Writer writer;
+
+    private boolean closed;
+
+    public NonBlockingPumpReader() {
+        this(DEFAULT_BUFFER_SIZE);
+    }
+
+    public NonBlockingPumpReader(int bufferSize) {
+        char[] buf = new char[bufferSize];
+        this.readBuffer = CharBuffer.wrap(buf);
+        this.writeBuffer = CharBuffer.wrap(buf);
+        this.writer = new NbpWriter();
+        // There are no bytes available to read after initialization
+        readBuffer.limit(0);
+    }
+
+    public Writer getWriter() {
+        return this.writer;
+    }
+
+    private int wait(CharBuffer buffer, long timeout) throws InterruptedIOException {
+        boolean isInfinite = (timeout <= 0L);
+        long end = 0;
+        if (!isInfinite) {
+            end = System.currentTimeMillis() + timeout;
+        }
+        while (!closed && !buffer.hasRemaining() && (isInfinite || timeout > 0L)) {
+            // Wake up waiting readers/writers
+            notifyAll();
+            try {
+                wait(timeout);
+            } catch (InterruptedException e) {
+                throw new InterruptedIOException();
+            }
+            if (!isInfinite) {
+                timeout = end - System.currentTimeMillis();
+            }
+        }
+        return closed
+                ? EOF
+                : buffer.hasRemaining()
+                    ? 0
+                    : READ_EXPIRED;
+    }
+
+    private static boolean rewind(CharBuffer buffer, CharBuffer other) {
+        // Extend limit of other buffer if there is additional input/output available
+        if (buffer.position() > other.position()) {
+            other.limit(buffer.position());
+        }
+        // If we have reached the end of the buffer, rewind and set the new limit
+        if (buffer.position() == buffer.capacity()) {
+            buffer.rewind();
+            buffer.limit(other.position());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public synchronized boolean ready() {
+        return readBuffer.hasRemaining();
+    }
+
+    public synchronized int available() {
+        int count = readBuffer.remaining();
+        if (writeBuffer.position() < readBuffer.position()) {
+            count += writeBuffer.position();
+        }
+        return count;
+    }
+
+    @Override
+    protected synchronized int read(long timeout, boolean isPeek) throws IOException {
+        // Blocks until more input is available or the reader is closed.
+        int res = wait(readBuffer, timeout);
+        if (res >= 0) {
+            res = isPeek ? readBuffer.get(readBuffer.position()) : readBuffer.get();
+        }
+        rewind(readBuffer, writeBuffer);
+        return res;
+    }
+
+    synchronized void write(char[] cbuf, int off, int len) throws IOException {
+        while (len > 0) {
+            // Blocks until there is new space available for buffering or the
+            // reader is closed.
+            if (wait(writeBuffer, 0L) == EOF) {
+                throw new ClosedException();
+            }
+            // Copy as much characters as we can
+            int count = Math.min(len, writeBuffer.remaining());
+            writeBuffer.put(cbuf, off, count);
+            off += count;
+            len -= count;
+            // Update buffer states and rewind if necessary
+            rewind(writeBuffer, readBuffer);
+        }
+    }
+
+    synchronized void flush() {
+        // Avoid waking up readers when there is nothing to read
+        if (readBuffer.hasRemaining()) {
+            // Notify readers
+            notifyAll();
+        }
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        this.closed = true;
+        notifyAll();
+    }
+
+    private class NbpWriter extends Writer {
+
+        @Override
+        public void write(char[] cbuf, int off, int len) throws IOException {
+            NonBlockingPumpReader.this.write(cbuf, off, len);
+        }
+
+        @Override
+        public void flush() throws IOException {
+            NonBlockingPumpReader.this.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            NonBlockingPumpReader.this.close();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Non blocking reader
+ */
+public abstract class NonBlockingReader extends Reader {
+    public static final int EOF = -1;
+    public static final int READ_EXPIRED = -2;
+
+    /**
+     * Shuts down the thread that is handling blocking I/O. Note that if the
+     * thread is currently blocked waiting for I/O it will not actually
+     * shut down until the I/O is received.
+     */
+    public void shutdown() {
+    }
+
+    @Override
+    public int read() throws IOException {
+        return read(0L, false);
+    }
+
+    /**
+     * Peeks to see if there is a byte waiting in the input stream without
+     * actually consuming the byte.
+     *
+     * @param timeout The amount of time to wait, 0 == forever
+     * @return -1 on eof, -2 if the timeout expired with no available input
+     * or the character that was read (without consuming it).
+     * @throws IOException if anything wrong happens
+     */
+    public int peek(long timeout) throws IOException {
+        return read(timeout, true);
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     *
+     * @param timeout The amount of time to wait for the character
+     * @return The character read, -1 if EOF is reached, or -2 if the
+     * read timed out.
+     * @throws IOException if anything wrong happens
+     */
+    public int read(long timeout) throws IOException {
+        return read(timeout, false);
+    }
+
+    /**
+     * This version of read() is very specific to jline's purposes, it
+     * will always always return a single byte at a time, rather than filling
+     * the entire buffer.
+     * @param b the buffer
+     * @param off the offset in the buffer
+     * @param len the maximum number of chars to read
+     * @throws IOException if anything wrong happens
+     */
+    @Override
+    public int read(char[] b, int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int c = this.read(0L);
+
+        if (c == EOF) {
+            return EOF;
+        }
+        b[off] = (char) c;
+        return 1;
+    }
+
+    public int available() {
+        return 0;
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     * @param timeout The amount of time to wait for the character
+     * @param isPeek <code>true</code>if the character read must not be consumed
+     * @return The character read, -1 if EOF is reached, or -2 if the
+     *   read timed out.
+     * @throws IOException if anything wrong happens
+     */
+    protected abstract int read(long timeout, boolean isPeek) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingReaderImpl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Reader;
+
+/**
+ * This class wraps a regular reader and allows it to appear as if it
+ * is non-blocking; that is, reads can be performed against it that timeout
+ * if no data is seen for a period of time.  This effect is achieved by having
+ * a separate thread perform all non-blocking read requests and then
+ * waiting on the thread to complete.
+ *
+ * <p>VERY IMPORTANT NOTES
+ * <ul>
+ *   <li> This class is not thread safe. It expects at most one reader.
+ *   <li> The {@link #shutdown()} method must be called in order to shut down
+ *          the thread that handles blocking I/O.
+ * </ul>
+ * @since 2.7
+ * @author Scott C. Gray &lt;scottgray1@gmail.com&gt;
+ */
+public class NonBlockingReaderImpl
+    extends NonBlockingReader
+{
+    public static final int READ_EXPIRED = -2;
+
+    private Reader in;                  // The actual input stream
+    private int    ch   = READ_EXPIRED; // Recently read character
+
+    private String      name;
+    private boolean     threadIsReading      = false;
+    private IOException exception            = null;
+    private long        threadDelay          = 60 * 1000;
+    private Thread      thread;
+
+    /**
+     * Creates a <code>NonBlockingReader</code> out of a normal blocking
+     * reader. Note that this call also spawn a separate thread to perform the
+     * blocking I/O on behalf of the thread that is using this class. The
+     * {@link #shutdown()} method must be called in order to shut this thread down.
+     * @param name The reader name
+     * @param in The reader to wrap
+     */
+    public NonBlockingReaderImpl(String name, Reader in) {
+        this.in = in;
+        this.name = name;
+    }
+
+    private synchronized void startReadingThreadIfNeeded() {
+        if (thread == null) {
+            thread = new Thread(this::run);
+            thread.setName(name + " non blocking reader thread");
+            thread.setDaemon(true);
+            thread.start();
+        }
+    }
+
+    /**
+     * Shuts down the thread that is handling blocking I/O. Note that if the
+     * thread is currently blocked waiting for I/O it will not actually
+     * shut down until the I/O is received.
+     */
+    public synchronized void shutdown() {
+        if (thread != null) {
+            notify();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        /*
+         * The underlying input stream is closed first. This means that if the
+         * I/O thread was blocked waiting on input, it will be woken for us.
+         */
+        in.close();
+        shutdown();
+    }
+
+    @Override
+    public synchronized boolean ready() throws IOException {
+        return ch >= 0 || in.ready();
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     * @param timeout The amount of time to wait for the character
+     * @return The character read, -1 if EOF is reached, or -2 if the
+     *   read timed out.
+     */
+    protected synchronized int read(long timeout, boolean isPeek) throws IOException {
+        /*
+         * If the thread hit an IOException, we report it.
+         */
+        if (exception != null) {
+            assert ch == READ_EXPIRED;
+            IOException toBeThrown = exception;
+            if (!isPeek)
+                exception = null;
+            throw toBeThrown;
+        }
+
+        /*
+         * If there was a pending character from the thread, then
+         * we send it. If the timeout is 0L or the thread was shut down
+         * then do a local read.
+         */
+        if (ch >= -1) {
+            assert exception == null;
+        }
+        else if (!isPeek && timeout <= 0L && !threadIsReading) {
+            ch = in.read();
+        }
+        else {
+            /*
+             * If the thread isn't reading already, then ask it to do so.
+             */
+            if (!threadIsReading) {
+                threadIsReading = true;
+                startReadingThreadIfNeeded();
+                notifyAll();
+            }
+
+            boolean isInfinite = (timeout <= 0L);
+
+            /*
+             * So the thread is currently doing the reading for us. So
+             * now we play the waiting game.
+             */
+            while (isInfinite || timeout > 0L)  {
+                long start = System.currentTimeMillis ();
+
+                try {
+                    if (Thread.interrupted()) {
+                        throw new InterruptedException();
+                    }
+                    wait(timeout);
+                }
+                catch (InterruptedException e) {
+                    exception = (IOException) new InterruptedIOException().initCause(e);
+                }
+
+                if (exception != null) {
+                    assert ch == READ_EXPIRED;
+
+                    IOException toBeThrown = exception;
+                    if (!isPeek)
+                        exception = null;
+                    throw toBeThrown;
+                }
+
+                if (ch >= -1) {
+                    assert exception == null;
+                    break;
+                }
+
+                if (!isInfinite) {
+                    timeout -= System.currentTimeMillis() - start;
+                }
+            }
+        }
+
+        /*
+         * ch is the character that was just read. Either we set it because
+         * a local read was performed or the read thread set it (or failed to
+         * change it).  We will return it's value, but if this was a peek
+         * operation, then we leave it in place.
+         */
+        int ret = ch;
+        if (!isPeek) {
+            ch = READ_EXPIRED;
+        }
+        return ret;
+    }
+
+    private void run () {
+        Log.debug("NonBlockingReader start");
+        boolean needToRead;
+
+        try {
+            while (true) {
+
+                /*
+                 * Synchronize to grab variables accessed by both this thread
+                 * and the accessing thread.
+                 */
+                synchronized (this) {
+                    needToRead = this.threadIsReading;
+
+                    try {
+                        /*
+                         * Nothing to do? Then wait.
+                         */
+                        if (!needToRead) {
+                            wait(threadDelay);
+                        }
+                    } catch (InterruptedException e) {
+                        /* IGNORED */
+                    }
+
+                    needToRead = this.threadIsReading;
+                    if (!needToRead) {
+                        return;
+                    }
+                }
+
+                /*
+                 * We're not shutting down, but we need to read. This cannot
+                 * happen while we are holding the lock (which we aren't now).
+                 */
+                int charRead = READ_EXPIRED;
+                IOException failure = null;
+                try {
+                    charRead = in.read();
+//                    if (charRead < 0) {
+//                        continue;
+//                    }
+                } catch (IOException e) {
+                    failure = e;
+//                    charRead = -1;
+                }
+
+                /*
+                 * Re-grab the lock to update the state.
+                 */
+                synchronized (this) {
+                    exception = failure;
+                    ch = charRead;
+                    threadIsReading = false;
+                    notify();
+                }
+            }
+        } catch (Throwable t) {
+            Log.warn("Error in NonBlockingReader thread", t);
+        } finally {
+            Log.debug("NonBlockingReader shutdown");
+            synchronized (this) {
+                thread = null;
+                threadIsReading = false;
+            }
+        }
+    }
+
+    public synchronized void clear() throws IOException {
+        while (ready()) {
+            read();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,83 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.File;
+
+public class OSUtils {
+
+    public static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
+
+    public static final boolean IS_CYGWIN = IS_WINDOWS
+            && System.getenv("PWD") != null
+            && System.getenv("PWD").startsWith("/");
+
+    @Deprecated
+    public static final boolean IS_MINGW = IS_WINDOWS
+            && System.getenv("MSYSTEM") != null
+            && System.getenv("MSYSTEM").startsWith("MINGW");
+
+    public static final boolean IS_MSYSTEM = IS_WINDOWS
+            && System.getenv("MSYSTEM") != null
+            && (System.getenv("MSYSTEM").startsWith("MINGW")
+                || System.getenv("MSYSTEM").equals("MSYS"));
+
+    public static final boolean IS_CONEMU = IS_WINDOWS
+            && System.getenv("ConEmuPID") != null;
+
+    public static final boolean IS_OSX = System.getProperty("os.name").toLowerCase().contains("mac");
+
+    public static String TTY_COMMAND;
+    public static String STTY_COMMAND;
+    public static String STTY_F_OPTION;
+    public static String INFOCMP_COMMAND;
+
+    static {
+        String tty;
+        String stty;
+        String sttyfopt;
+        String infocmp;
+        if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
+            tty = "tty.exe";
+            stty = "stty.exe";
+            sttyfopt = null;
+            infocmp = "infocmp.exe";
+            String path = System.getenv("PATH");
+            if (path != null) {
+                String[] paths = path.split(";");
+                for (String p : paths) {
+                    if (tty == null && new File(p, "tty.exe").exists()) {
+                        tty = new File(p, "tty.exe").getAbsolutePath();
+                    }
+                    if (stty == null && new File(p, "stty.exe").exists()) {
+                        stty = new File(p, "stty.exe").getAbsolutePath();
+                    }
+                    if (infocmp == null && new File(p, "infocmp.exe").exists()) {
+                        infocmp = new File(p, "infocmp.exe").getAbsolutePath();
+                    }
+                }
+            }
+        } else {
+            tty = "tty";
+            stty = "stty";
+            infocmp = "infocmp";
+            if (IS_OSX) {
+                sttyfopt = "-f";
+            }
+            else {
+                sttyfopt = "-F";
+            }
+        }
+        TTY_COMMAND = tty;
+        STTY_COMMAND = stty;
+        STTY_F_OPTION = sttyfopt;
+        INFOCMP_COMMAND = infocmp;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Reader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+public class PumpReader extends Reader {
+
+    private static final int EOF = -1;
+    private static final int DEFAULT_BUFFER_SIZE = 4096;
+
+    // Read and write buffer are backed by the same array
+    private final CharBuffer readBuffer;
+    private final CharBuffer writeBuffer;
+
+    private final Writer writer;
+
+    private boolean closed;
+
+    public PumpReader() {
+        this(DEFAULT_BUFFER_SIZE);
+    }
+
+    public PumpReader(int bufferSize) {
+        char[] buf = new char[bufferSize];
+        this.readBuffer = CharBuffer.wrap(buf);
+        this.writeBuffer = CharBuffer.wrap(buf);
+        this.writer = new Writer(this);
+
+        // There are no bytes available to read after initialization
+        readBuffer.limit(0);
+    }
+
+    public java.io.Writer getWriter() {
+        return this.writer;
+    }
+
+    public java.io.InputStream createInputStream(Charset charset) {
+        return new InputStream(this, charset);
+    }
+
+    private boolean wait(CharBuffer buffer) throws InterruptedIOException {
+        if (closed) {
+            return false;
+        }
+
+        while (!buffer.hasRemaining()) {
+            // Wake up waiting readers/writers
+            notifyAll();
+
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                throw new InterruptedIOException();
+            }
+
+            if (closed) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Blocks until more input is available or the reader is closed.
+     *
+     * @return true if more input is available, false if the reader is closed
+     * @throws InterruptedIOException If {@link #wait()} is interrupted
+     */
+    private boolean waitForInput() throws InterruptedIOException {
+        return wait(readBuffer);
+    }
+
+    /**
+     * Blocks until there is new space available for buffering or the
+     * reader is closed.
+     *
+     * @throws InterruptedIOException If {@link #wait()} is interrupted
+     * @throws ClosedException If the reader was closed
+     */
+    private void waitForBufferSpace() throws InterruptedIOException, ClosedException {
+        if (!wait(writeBuffer)) {
+            throw new ClosedException();
+        }
+    }
+
+    private static boolean rewind(CharBuffer buffer, CharBuffer other) {
+        // Extend limit of other buffer if there is additional input/output available
+        if (buffer.position() > other.position()) {
+            other.limit(buffer.position());
+        }
+
+        // If we have reached the end of the buffer, rewind and set the new limit
+        if (buffer.position() == buffer.capacity()) {
+            buffer.rewind();
+            buffer.limit(other.position());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Attempts to find additional input by rewinding the {@link #readBuffer}.
+     * Updates the {@link #writeBuffer} to make read bytes available for buffering.
+     *
+     * @return If more input is available
+     */
+    private boolean rewindReadBuffer() {
+        return rewind(readBuffer, writeBuffer) && readBuffer.hasRemaining();
+    }
+
+    /**
+     * Attempts to find additional buffer space by rewinding the {@link #writeBuffer}.
+     * Updates the {@link #readBuffer} to make written bytes available to the reader.
+     */
+    private void rewindWriteBuffer() {
+        rewind(writeBuffer, readBuffer);
+    }
+
+    @Override
+    public synchronized boolean ready() {
+        return readBuffer.hasRemaining();
+    }
+
+    public synchronized int available() {
+        int count = readBuffer.remaining();
+        if (writeBuffer.position() < readBuffer.position()) {
+            count += writeBuffer.position();
+        }
+        return count;
+    }
+
+    @Override
+    public synchronized int read() throws IOException {
+        if (!waitForInput()) {
+            return EOF;
+        }
+
+        int b = readBuffer.get();
+        rewindReadBuffer();
+        return b;
+    }
+
+    private int copyFromBuffer(char[] cbuf, int off, int len) {
+        len = Math.min(len, readBuffer.remaining());
+        readBuffer.get(cbuf, off, len);
+        return len;
+    }
+
+    @Override
+    public synchronized int read(char[] cbuf, int off, int len) throws IOException {
+        if (len == 0) {
+            return 0;
+        }
+
+        if (!waitForInput()) {
+            return EOF;
+        }
+
+        int count = copyFromBuffer(cbuf, off, len);
+        if (rewindReadBuffer() && count < len) {
+            count += copyFromBuffer(cbuf, off + count, len - count);
+            rewindReadBuffer();
+        }
+
+        return count;
+    }
+
+    @Override
+    public int read(CharBuffer target) throws IOException {
+        if (!target.hasRemaining()) {
+            return 0;
+        }
+
+        if (!waitForInput()) {
+            return EOF;
+        }
+
+        int count = readBuffer.read(target);
+        if (rewindReadBuffer() && target.hasRemaining()) {
+            count += readBuffer.read(target);
+            rewindReadBuffer();
+        }
+
+        return count;
+    }
+
+    private void encodeBytes(CharsetEncoder encoder, ByteBuffer output) throws IOException {
+        CoderResult result = encoder.encode(readBuffer, output, false);
+        if (rewindReadBuffer() && result.isUnderflow()) {
+            encoder.encode(readBuffer, output, false);
+            rewindReadBuffer();
+        }
+    }
+
+    synchronized int readBytes(CharsetEncoder encoder, byte[] b, int off, int len) throws IOException {
+        if (!waitForInput()) {
+            return 0;
+        }
+
+        ByteBuffer output = ByteBuffer.wrap(b, off, len);
+        encodeBytes(encoder, output);
+        return output.position() - off;
+    }
+
+    synchronized void readBytes(CharsetEncoder encoder, ByteBuffer output) throws IOException {
+        if (!waitForInput()) {
+            return;
+        }
+
+        encodeBytes(encoder, output);
+    }
+
+    synchronized void write(char c) throws IOException {
+        waitForBufferSpace();
+        writeBuffer.put(c);
+        rewindWriteBuffer();
+    }
+
+    synchronized void write(char[] cbuf, int off, int len) throws IOException {
+        while (len > 0) {
+            waitForBufferSpace();
+
+            // Copy as much characters as we can
+            int count = Math.min(len, writeBuffer.remaining());
+            writeBuffer.put(cbuf, off, count);
+
+            off += count;
+            len -= count;
+
+            // Update buffer states and rewind if necessary
+            rewindWriteBuffer();
+        }
+    }
+
+    synchronized void write(String str, int off, int len) throws IOException {
+        char[] buf = writeBuffer.array();
+
+        while (len > 0) {
+            waitForBufferSpace();
+
+            // Copy as much characters as we can
+            int count = Math.min(len, writeBuffer.remaining());
+            // CharBuffer.put(String) doesn't use getChars so do it manually
+            str.getChars(off, off + count, buf, writeBuffer.position());
+            writeBuffer.position(writeBuffer.position() + count);
+
+            off += count;
+            len -= count;
+
+            // Update buffer states and rewind if necessary
+            rewindWriteBuffer();
+        }
+    }
+
+    synchronized void flush() {
+        // Avoid waking up readers when there is nothing to read
+        if (readBuffer.hasRemaining()) {
+            // Notify readers
+            notifyAll();
+        }
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        this.closed = true;
+        notifyAll();
+    }
+
+    private static class Writer extends java.io.Writer {
+
+        private final PumpReader reader;
+
+        private Writer(PumpReader reader) {
+            this.reader = reader;
+        }
+
+        @Override
+        public void write(int c) throws IOException {
+            reader.write((char) c);
+        }
+
+        @Override
+        public void write(char[] cbuf, int off, int len) throws IOException {
+            reader.write(cbuf, off, len);
+        }
+
+        @Override
+        public void write(String str, int off, int len) throws IOException {
+            reader.write(str, off, len);
+        }
+
+        @Override
+        public void flush() throws IOException {
+            reader.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            reader.close();
+        }
+
+    }
+
+    private static class InputStream extends java.io.InputStream {
+
+        private final PumpReader reader;
+        private final CharsetEncoder encoder;
+
+        // To encode a character with multiple bytes (e.g. certain Unicode characters)
+        // we need enough space to encode them. Reading would fail if the read() method
+        // is used to read a single byte in these cases.
+        // Use this buffer to ensure we always have enough space to encode a character.
+        private final ByteBuffer buffer;
+
+        private InputStream(PumpReader reader, Charset charset) {
+            this.reader = reader;
+            this.encoder = charset.newEncoder()
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE)
+                    .onMalformedInput(CodingErrorAction.REPLACE);
+            this.buffer = ByteBuffer.allocate((int) Math.ceil(encoder.maxBytesPerChar()));
+
+            // No input available after initialization
+            buffer.limit(0);
+        }
+
+        @Override
+        public int available() throws IOException {
+            return (int) (reader.available() * (double) this.encoder.averageBytesPerChar()) + buffer.remaining();
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (!buffer.hasRemaining() && !readUsingBuffer()) {
+                return EOF;
+            }
+
+            return buffer.get();
+        }
+
+        private boolean readUsingBuffer() throws IOException {
+            buffer.clear(); // Reset buffer
+            reader.readBytes(encoder, buffer);
+            buffer.flip();
+            return buffer.hasRemaining();
+        }
+
+        private int copyFromBuffer(byte[] b, int off, int len) {
+            len = Math.min(len, buffer.remaining());
+            buffer.get(b, off, len);
+            return len;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (len == 0) {
+                return 0;
+            }
+
+            int read;
+            if (buffer.hasRemaining()) {
+                read = copyFromBuffer(b, off, len);
+                if (read == len) {
+                    return len;
+                }
+
+                off += read;
+                len -= read;
+            } else {
+                read = 0;
+            }
+
+            // Do we have enough space to avoid buffering?
+            if (len >= buffer.capacity()) {
+                read += reader.readBytes(this.encoder, b, off, len);
+            } else if (readUsingBuffer()) {
+                read += copyFromBuffer(b, off, len);
+            }
+
+            // Return EOF if we didn't read any bytes
+            return read == 0 ? EOF : read;
+        }
+
+        @Override
+        public void close() throws IOException {
+            reader.close();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ShutdownHooks.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,107 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Manages the JLine shutdown-hook thread and tasks to execute on shutdown.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.7
+ */
+public final class ShutdownHooks
+{
+    private static final List<Task> tasks = new ArrayList<>();
+
+    private static Thread hook;
+
+    public static synchronized <T extends Task> T add(final T task) {
+        Objects.requireNonNull(task);
+
+        // Install the hook thread if needed
+        if (hook == null) {
+            hook = addHook(new Thread("JLine Shutdown Hook")
+            {
+                @Override
+                public void run() {
+                    runTasks();
+                }
+            });
+        }
+
+        // Track the task
+        Log.debug("Adding shutdown-hook task: ", task);
+        tasks.add(task);
+
+        return task;
+    }
+
+    private static synchronized void runTasks() {
+        Log.debug("Running all shutdown-hook tasks");
+
+        // Iterate through copy of tasks list
+        for (Task task : tasks.toArray(new Task[tasks.size()])) {
+            Log.debug("Running task: ", task);
+            try {
+                task.run();
+            }
+            catch (Throwable e) {
+                Log.warn("Task failed", e);
+            }
+        }
+
+        tasks.clear();
+    }
+
+    private static Thread addHook(final Thread thread) {
+        Log.debug("Registering shutdown-hook: ", thread);
+        Runtime.getRuntime().addShutdownHook(thread);
+        return thread;
+    }
+
+    public static synchronized void remove(final Task task) {
+        Objects.requireNonNull(task);
+
+        // ignore if hook never installed
+        if (hook == null) {
+            return;
+        }
+
+        // Drop the task
+        tasks.remove(task);
+
+        // If there are no more tasks, then remove the hook thread
+        if (tasks.isEmpty()) {
+            removeHook(hook);
+            hook = null;
+        }
+    }
+
+    private static void removeHook(final Thread thread) {
+        Log.debug("Removing shutdown-hook: ", thread);
+
+        try {
+            Runtime.getRuntime().removeShutdownHook(thread);
+        }
+        catch (IllegalStateException e) {
+            // The VM is shutting down, not a big deal; ignore
+        }
+    }
+
+    /**
+     * Essentially a {@link Runnable} which allows running to throw an exception.
+     */
+    public interface Task
+    {
+        void run() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,115 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.lang.reflect.Proxy;
+import java.util.Objects;
+
+/**
+ * Signals helpers.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 3.0
+ */
+public final class Signals {
+
+    private Signals() {
+    }
+
+    /**
+     *
+     * @param name the signal, CONT, STOP, etc...
+     * @param handler the callback to run
+     *
+     * @return an object that needs to be passed to the {@link #unregister(String, Object)}
+     *         method to unregister the handler
+     */
+    public static Object register(String name, Runnable handler) {
+        Objects.requireNonNull(handler);
+        return register(name, handler, handler.getClass().getClassLoader());
+    }
+
+    public static Object register(String name, final Runnable handler, ClassLoader loader) {
+        try {
+            Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
+            // Implement signal handler
+            Object signalHandler = Proxy.newProxyInstance(loader,
+                    new Class<?>[]{signalHandlerClass}, (proxy, method, args) -> {
+                        // only method we are proxying is handle()
+                        if (method.getDeclaringClass() == Object.class) {
+                            if ("toString".equals(method.getName())) {
+                                return handler.toString();
+                            }
+                        } else if (method.getDeclaringClass() == signalHandlerClass) {
+                            Log.trace(() -> "Calling handler " + toString(handler) + " for signal " + name);
+                            handler.run();
+                        }
+                        return null;
+                    });
+            return doRegister(name, signalHandler);
+        } catch (Exception e) {
+            // Ignore this one too, if the above failed, the signal API is incompatible with what we're expecting
+            Log.debug("Error registering handler for signal ", name, e);
+            return null;
+        }
+    }
+
+    public static Object registerDefault(String name) {
+        try {
+            Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
+            return doRegister(name, signalHandlerClass.getField("SIG_DFL").get(null));
+        } catch (Exception e) {
+            // Ignore this one too, if the above failed, the signal API is incompatible with what we're expecting
+            Log.debug("Error registering default handler for signal ", name, e);
+            return null;
+        }
+    }
+
+    public static void unregister(String name, Object previous) {
+        try {
+            // We should make sure the current signal is the one we registered
+            if (previous != null) {
+                doRegister(name, previous);
+            }
+        } catch (Exception e) {
+            // Ignore
+            Log.debug("Error unregistering handler for signal ", name, e);
+        }
+    }
+
+    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"))) {
+            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);
+    }
+
+    @SuppressWarnings("")
+    private static String toString(Object handler) {
+        try {
+            Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
+            if (handler == signalHandlerClass.getField("SIG_DFL").get(null)) {
+                return "SIG_DFL";
+            }
+            if (handler == signalHandlerClass.getField("SIG_IGN").get(null)) {
+                return "SIG_IGN";
+            }
+        } catch (Throwable t) {
+            // ignore
+        }
+        return handler != null ? handler.toString() : "null";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Status.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.Objects;
+import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.Terminal.Signal;
+import jdk.internal.org.jline.terminal.Terminal.SignalHandler;
+import jdk.internal.org.jline.terminal.impl.AbstractTerminal;
+import jdk.internal.org.jline.utils.InfoCmp.Capability;
+import jdk.internal.org.jline.terminal.Size;
+
+public class Status {
+
+    protected final AbstractTerminal terminal;
+    protected final boolean supported;
+    protected List<AttributedString> oldLines = Collections.emptyList();
+    protected int rows;
+    protected int columns;
+    protected boolean force;
+
+    public static Status getStatus(Terminal terminal) {
+        return getStatus(terminal, true);
+    }
+
+    public static Status getStatus(Terminal terminal, boolean create) {
+        return terminal instanceof AbstractTerminal
+                ? ((AbstractTerminal) terminal).getStatus(create)
+                : null;
+    }
+
+
+    public Status(AbstractTerminal terminal) {
+        this.terminal = Objects.requireNonNull(terminal, "terminal can not be null");
+        this.supported = terminal.getStringCapability(Capability.change_scroll_region) != null
+            && terminal.getStringCapability(Capability.save_cursor) != null
+            && terminal.getStringCapability(Capability.restore_cursor) != null
+            && terminal.getStringCapability(Capability.cursor_address) != null;
+        if (supported) {
+            resize();
+        }
+    }
+
+    public void resize() {
+        Size size = terminal.getSize();
+        this.rows = size.getRows();
+        this.columns = size.getColumns();
+        this.force = true;
+    }
+
+    public void reset() {
+        this.force = true;
+    }
+
+    public void redraw() {
+        update(oldLines);
+    }
+
+    public void update(List<AttributedString> lines) {
+        if (lines == null) {
+            lines = Collections.emptyList();
+        }
+        if (!supported || (oldLines.equals(lines) && !force)) {
+            return;
+        }
+        int nb = lines.size() - oldLines.size();
+        if (nb > 0) {
+            for (int i = 0; i < nb; i++) {
+                terminal.puts(Capability.cursor_down);
+            }
+            for (int i = 0; i < nb; i++) {
+                terminal.puts(Capability.cursor_up);
+            }
+        }
+        terminal.puts(Capability.save_cursor);
+        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));
+        }
+        terminal.puts(Capability.change_scroll_region, 0, rows - 1 - lines.size());
+        terminal.puts(Capability.restore_cursor);
+        terminal.flush();
+        oldLines = new ArrayList<>(lines);
+        force = false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,322 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.utils;
+
+import java.util.Locale;
+import java.util.function.Function;
+//import java.util.logging.Level;
+//import java.util.logging.Logger;
+
+import static java.util.Objects.requireNonNull;
+import static jdk.internal.org.jline.utils.AttributedStyle.*;
+
+// TODO: document style specification
+
+/**
+ * Resolves named (or source-referenced) {@link AttributedStyle}.
+ *
+ * @since 3.6
+ */
+public class StyleResolver {
+//    private static final Logger log = Logger.getLogger(StyleResolver.class.getName());
+
+    private final Function<String, String> source;
+
+    public StyleResolver(final Function<String, String> source) {
+        this.source = requireNonNull(source);
+    }
+
+    /**
+     * Returns the color identifier for the given name.
+     * <p>
+     * Bright color can be specified with: {@code !<color>} or {@code bright-<color>}.
+     * <p>
+     * Full xterm256 color can be specified with: {@code ~<color>}.
+     *
+     * @param name the name of the color
+     * @return color code, or {@code null} if unable to determine.
+     */
+    private static Integer color(String name) {
+        int flags = 0;
+        name = name.toLowerCase(Locale.US);
+
+        // extract bright flag from color name
+        if (name.charAt(0) == '!') {
+            name = name.substring(1, name.length());
+            flags = BRIGHT;
+        } else if (name.startsWith("bright-")) {
+            name = name.substring(7, name.length());
+            flags = BRIGHT;
+        } else if (name.charAt(0) == '~') {
+            try {
+                // TODO: if the palette is not the default one, should be
+                // TODO: translate into 24-bits first and let the #toAnsi() call
+                // TODO: round with the current palette ?
+                name = name.substring(1, name.length());
+                return Colors.rgbColor(name);
+            } catch (IllegalArgumentException e) {
+//                log.warning("Invalid style-color name: " + name);
+                return null;
+            }
+        }
+
+        switch (name) {
+            case "black":
+            case "k":
+                return flags + BLACK;
+
+            case "red":
+            case "r":
+                return flags + RED;
+
+            case "green":
+            case "g":
+                return flags + GREEN;
+
+            case "yellow":
+            case "y":
+                return flags + YELLOW;
+
+            case "blue":
+            case "b":
+                return flags + BLUE;
+
+            case "magenta":
+            case "m":
+                return flags + MAGENTA;
+
+            case "cyan":
+            case "c":
+                return flags + CYAN;
+
+            case "white":
+            case "w":
+                return flags + WHITE;
+        }
+
+        return null;
+    }
+
+    // TODO: could consider a small cache to reduce style calculations?
+
+    /**
+     * Resolve the given style specification.
+     * <p>
+     * If for some reason the specification is invalid, then {@link AttributedStyle#DEFAULT} will be used.
+     *
+     * @param spec the specification
+     * @return the style
+     */
+    public AttributedStyle resolve(final String spec) {
+        requireNonNull(spec);
+
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Resolve: " + spec);
+//        }
+
+        int i = spec.indexOf(":-");
+        if (i != -1) {
+            String[] parts = spec.split(":-");
+            return resolve(parts[0].trim(), parts[1].trim());
+        }
+
+        return apply(DEFAULT, spec);
+    }
+
+    /**
+     * Resolve the given style specification.
+     * <p>
+     * If this resolves to {@link AttributedStyle#DEFAULT} then given default specification is used if non-null.
+     *
+     * @param spec the specification
+     * @param defaultSpec the default specifiaction
+     * @return the style
+     */
+    public AttributedStyle resolve(final String spec, final String defaultSpec) {
+        requireNonNull(spec);
+
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest(String.format("Resolve: %s; default: %s", spec, defaultSpec));
+//        }
+
+        AttributedStyle style = apply(DEFAULT, spec);
+        if (style == DEFAULT && defaultSpec != null) {
+            style = apply(style, defaultSpec);
+        }
+        return style;
+    }
+
+    /**
+     * Apply style specification.
+     *
+     * @param style the style to apply to
+     * @param spec the specification
+     * @return the new style
+     */
+    private AttributedStyle apply(AttributedStyle style, final String spec) {
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Apply: " + spec);
+//        }
+
+        for (String item : spec.split(",")) {
+            item = item.trim();
+            if (item.isEmpty()) {
+                continue;
+            }
+
+            if (item.startsWith(".")) {
+                style = applyReference(style, item);
+            } else if (item.contains(":")) {
+                style = applyColor(style, item);
+            } else if (item.matches("[0-9]+(;[0-9]+)*")) {
+                style = applyAnsi(style, item);
+            } else {
+                style = applyNamed(style, item);
+            }
+        }
+
+        return style;
+    }
+
+    private AttributedStyle applyAnsi(final AttributedStyle style, final String spec) {
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Apply-ansi: " + spec);
+//        }
+
+        return new AttributedStringBuilder()
+                .style(style)
+                .ansiAppend("\033[" + spec + "m")
+                .style();
+    }
+
+    /**
+     * Apply source-referenced named style.
+     *
+     * @param style the style to apply to
+     * @param spec the specification
+     * @return the new style
+     */
+    private AttributedStyle applyReference(final AttributedStyle style, final String spec) {
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Apply-reference: " + spec);
+//        }
+
+        if (spec.length() == 1) {
+//            log.warning("Invalid style-reference; missing discriminator: " + spec);
+        } else {
+            String name = spec.substring(1, spec.length());
+            String resolvedSpec = source.apply(name);
+            if (resolvedSpec != null) {
+                return apply(style, resolvedSpec);
+            }
+            // null is normal if source has not be configured with named style
+        }
+
+        return style;
+    }
+
+    /**
+     * Apply default named styles.
+     *
+     * @param style the style to apply to
+     * @param name the named style
+     * @return the new style
+     */
+    private AttributedStyle applyNamed(final AttributedStyle style, final String name) {
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Apply-named: " + name);
+//        }
+
+        // TODO: consider short aliases for named styles
+
+        switch (name.toLowerCase(Locale.US)) {
+            case "default":
+                return DEFAULT;
+
+            case "bold":
+                return style.bold();
+
+            case "faint":
+                return style.faint();
+
+            case "italic":
+                return style.italic();
+
+            case "underline":
+                return style.underline();
+
+            case "blink":
+                return style.blink();
+
+            case "inverse":
+                return style.inverse();
+
+            case "inverse-neg":
+            case "inverseneg":
+                return style.inverseNeg();
+
+            case "conceal":
+                return style.conceal();
+
+            case "crossed-out":
+            case "crossedout":
+                return style.crossedOut();
+
+            case "hidden":
+                return style.hidden();
+
+            default:
+//                log.warning("Unknown style: " + name);
+                return style;
+        }
+    }
+
+    // TODO: consider simplify and always using StyleColor, for now for compat with other bits leaving syntax complexity
+
+    /**
+     * Apply color styles specification.
+     *
+     * @param style The style to apply to
+     * @param spec  Color specification: {@code <color-mode>:<color-name>}
+     * @return      The new style
+     */
+    private AttributedStyle applyColor(final AttributedStyle style, final String spec) {
+//        if (log.isLoggable(Level.FINEST)) {
+//            log.finest("Apply-color: " + spec);
+//        }
+
+        // extract color-mode:color-name
+        String[] parts = spec.split(":", 2);
+        String colorMode = parts[0].trim();
+        String colorName = parts[1].trim();
+
+        // resolve the color-name
+        Integer color = color(colorName);
+        if (color == null) {
+//            log.warning("Invalid color-name: " + colorName);
+        } else {
+            // resolve and apply color-mode
+            switch (colorMode.toLowerCase(Locale.US)) {
+                case "foreground":
+                case "fg":
+                case "f":
+                    return style.foreground(color);
+
+                case "background":
+                case "bg":
+                case "b":
+                    return style.background(color);
+
+                default:
+//                    log.warning("Invalid color-mode: " + colorMode);
+            }
+        }
+        return style;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WCWidth.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,161 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.utils;
+
+public final class WCWidth {
+
+    private WCWidth() {
+    }
+
+    /* The following two functions define the column width of an ISO 10646
+     * character as follows:
+     *
+     *    - The null character (U+0000) has a column width of 0.
+     *
+     *    - Other C0/C1 control characters and DEL will lead to a return
+     *      value of -1.
+     *
+     *    - Non-spacing and enclosing combining characters (general
+     *      category code Mn or Me in the Unicode database) have a
+     *      column width of 0.
+     *
+     *    - SOFT HYPHEN (U+00AD) has a column width of 1.
+     *
+     *    - Other format characters (general category code Cf in the Unicode
+     *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+     *
+     *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+     *      have a column width of 0.
+     *
+     *    - Spacing characters in the East Asian Wide (W) or East Asian
+     *      Full-width (F) category as defined in Unicode Technical
+     *      Report #11 have a column width of 2.
+     *
+     *    - All remaining characters (including all printable
+     *      ISO 8859-1 and WGL4 characters, Unicode control characters,
+     *      etc.) have a column width of 1.
+     *
+     * This implementation assumes that wchar_t characters are encoded
+     * in ISO 10646.
+     */
+    public static int wcwidth(int ucs)
+    {
+
+        /* test for 8-bit control characters */
+        if (ucs == 0)
+            return 0;
+        if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+            return -1;
+
+        /* binary search in table of non-spacing characters */
+        if (bisearch(ucs, combining, combining.length - 1))
+            return 0;
+
+        /* if we arrive here, ucs is not a combining or C0/C1 control character */
+        return 1 +
+                ((ucs >= 0x1100 &&
+                        (ucs <= 0x115f ||                           /* Hangul Jamo init. consonants */
+                                ucs == 0x2329 || ucs == 0x232a ||
+                                (ucs >= 0x2e80 && ucs <= 0xa4cf &&
+                                        ucs != 0x303f) ||           /* CJK ... Yi */
+                                (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+                                (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+                                (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+                                (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+                                (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+                                (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+                                (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+                                (ucs >= 0x30000 && ucs <= 0x3fffd))) ? 1 : 0);
+    }
+
+    /* sorted list of non-overlapping intervals of non-spacing characters */
+    /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+    static Interval[] combining = {
+            new Interval( 0x0300, 0x036F ), new Interval( 0x0483, 0x0486 ), new Interval( 0x0488, 0x0489 ),
+            new Interval( 0x0591, 0x05BD ), new Interval( 0x05BF, 0x05BF ), new Interval( 0x05C1, 0x05C2 ),
+            new Interval( 0x05C4, 0x05C5 ), new Interval( 0x05C7, 0x05C7 ), new Interval( 0x0600, 0x0603 ),
+            new Interval( 0x0610, 0x0615 ), new Interval( 0x064B, 0x065E ), new Interval( 0x0670, 0x0670 ),
+            new Interval( 0x06D6, 0x06E4 ), new Interval( 0x06E7, 0x06E8 ), new Interval( 0x06EA, 0x06ED ),
+            new Interval( 0x070F, 0x070F ), new Interval( 0x0711, 0x0711 ), new Interval( 0x0730, 0x074A ),
+            new Interval( 0x07A6, 0x07B0 ), new Interval( 0x07EB, 0x07F3 ), new Interval( 0x0901, 0x0902 ),
+            new Interval( 0x093C, 0x093C ), new Interval( 0x0941, 0x0948 ), new Interval( 0x094D, 0x094D ),
+            new Interval( 0x0951, 0x0954 ), new Interval( 0x0962, 0x0963 ), new Interval( 0x0981, 0x0981 ),
+            new Interval( 0x09BC, 0x09BC ), new Interval( 0x09C1, 0x09C4 ), new Interval( 0x09CD, 0x09CD ),
+            new Interval( 0x09E2, 0x09E3 ), new Interval( 0x0A01, 0x0A02 ), new Interval( 0x0A3C, 0x0A3C ),
+            new Interval( 0x0A41, 0x0A42 ), new Interval( 0x0A47, 0x0A48 ), new Interval( 0x0A4B, 0x0A4D ),
+            new Interval( 0x0A70, 0x0A71 ), new Interval( 0x0A81, 0x0A82 ), new Interval( 0x0ABC, 0x0ABC ),
+            new Interval( 0x0AC1, 0x0AC5 ), new Interval( 0x0AC7, 0x0AC8 ), new Interval( 0x0ACD, 0x0ACD ),
+            new Interval( 0x0AE2, 0x0AE3 ), new Interval( 0x0B01, 0x0B01 ), new Interval( 0x0B3C, 0x0B3C ),
+            new Interval( 0x0B3F, 0x0B3F ), new Interval( 0x0B41, 0x0B43 ), new Interval( 0x0B4D, 0x0B4D ),
+            new Interval( 0x0B56, 0x0B56 ), new Interval( 0x0B82, 0x0B82 ), new Interval( 0x0BC0, 0x0BC0 ),
+            new Interval( 0x0BCD, 0x0BCD ), new Interval( 0x0C3E, 0x0C40 ), new Interval( 0x0C46, 0x0C48 ),
+            new Interval( 0x0C4A, 0x0C4D ), new Interval( 0x0C55, 0x0C56 ), new Interval( 0x0CBC, 0x0CBC ),
+            new Interval( 0x0CBF, 0x0CBF ), new Interval( 0x0CC6, 0x0CC6 ), new Interval( 0x0CCC, 0x0CCD ),
+            new Interval( 0x0CE2, 0x0CE3 ), new Interval( 0x0D41, 0x0D43 ), new Interval( 0x0D4D, 0x0D4D ),
+            new Interval( 0x0DCA, 0x0DCA ), new Interval( 0x0DD2, 0x0DD4 ), new Interval( 0x0DD6, 0x0DD6 ),
+            new Interval( 0x0E31, 0x0E31 ), new Interval( 0x0E34, 0x0E3A ), new Interval( 0x0E47, 0x0E4E ),
+            new Interval( 0x0EB1, 0x0EB1 ), new Interval( 0x0EB4, 0x0EB9 ), new Interval( 0x0EBB, 0x0EBC ),
+            new Interval( 0x0EC8, 0x0ECD ), new Interval( 0x0F18, 0x0F19 ), new Interval( 0x0F35, 0x0F35 ),
+            new Interval( 0x0F37, 0x0F37 ), new Interval( 0x0F39, 0x0F39 ), new Interval( 0x0F71, 0x0F7E ),
+            new Interval( 0x0F80, 0x0F84 ), new Interval( 0x0F86, 0x0F87 ), new Interval( 0x0F90, 0x0F97 ),
+            new Interval( 0x0F99, 0x0FBC ), new Interval( 0x0FC6, 0x0FC6 ), new Interval( 0x102D, 0x1030 ),
+            new Interval( 0x1032, 0x1032 ), new Interval( 0x1036, 0x1037 ), new Interval( 0x1039, 0x1039 ),
+            new Interval( 0x1058, 0x1059 ), new Interval( 0x1160, 0x11FF ), new Interval( 0x135F, 0x135F ),
+            new Interval( 0x1712, 0x1714 ), new Interval( 0x1732, 0x1734 ), new Interval( 0x1752, 0x1753 ),
+            new Interval( 0x1772, 0x1773 ), new Interval( 0x17B4, 0x17B5 ), new Interval( 0x17B7, 0x17BD ),
+            new Interval( 0x17C6, 0x17C6 ), new Interval( 0x17C9, 0x17D3 ), new Interval( 0x17DD, 0x17DD ),
+            new Interval( 0x180B, 0x180D ), new Interval( 0x18A9, 0x18A9 ), new Interval( 0x1920, 0x1922 ),
+            new Interval( 0x1927, 0x1928 ), new Interval( 0x1932, 0x1932 ), new Interval( 0x1939, 0x193B ),
+            new Interval( 0x1A17, 0x1A18 ), new Interval( 0x1B00, 0x1B03 ), new Interval( 0x1B34, 0x1B34 ),
+            new Interval( 0x1B36, 0x1B3A ), new Interval( 0x1B3C, 0x1B3C ), new Interval( 0x1B42, 0x1B42 ),
+            new Interval( 0x1B6B, 0x1B73 ), new Interval( 0x1DC0, 0x1DCA ), new Interval( 0x1DFE, 0x1DFF ),
+            new Interval( 0x200B, 0x200F ), new Interval( 0x202A, 0x202E ), new Interval( 0x2060, 0x2063 ),
+            new Interval( 0x206A, 0x206F ), new Interval( 0x20D0, 0x20EF ), new Interval( 0x302A, 0x302F ),
+            new Interval( 0x3099, 0x309A ), new Interval( 0xA806, 0xA806 ), new Interval( 0xA80B, 0xA80B ),
+            new Interval( 0xA825, 0xA826 ), new Interval( 0xFB1E, 0xFB1E ), new Interval( 0xFE00, 0xFE0F ),
+            new Interval( 0xFE20, 0xFE23 ), new Interval( 0xFEFF, 0xFEFF ), new Interval( 0xFFF9, 0xFFFB ),
+            new Interval( 0x10A01, 0x10A03 ), new Interval( 0x10A05, 0x10A06 ), new Interval( 0x10A0C, 0x10A0F ),
+            new Interval( 0x10A38, 0x10A3A ), new Interval( 0x10A3F, 0x10A3F ), new Interval( 0x1D167, 0x1D169 ),
+            new Interval( 0x1D173, 0x1D182 ), new Interval( 0x1D185, 0x1D18B ), new Interval( 0x1D1AA, 0x1D1AD ),
+            new Interval( 0x1D242, 0x1D244 ), new Interval( 0xE0001, 0xE0001 ), new Interval( 0xE0020, 0xE007F ),
+            new Interval( 0xE0100, 0xE01EF )
+    };
+
+    private static class Interval {
+        public final int first;
+        public final int last;
+
+        public Interval(int first, int last) {
+            this.first = first;
+            this.last = last;
+        }
+    }
+
+    /* auxiliary function for binary search in interval table */
+    private static boolean bisearch(int ucs, Interval[] table, int max) {
+        int min = 0;
+        int mid;
+
+        if (ucs < table[0].first || ucs > table[max].last)
+            return false;
+        while (max >= min) {
+            mid = (min + max) / 2;
+            if (ucs > table[mid].last)
+                min = mid + 1;
+            else if (ucs < table[mid].first)
+                max = mid - 1;
+            else
+                return true;
+        }
+
+        return false;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/WriterOutputStream.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.utils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * Redirects an {@link OutputStream} to a {@link Writer} by decoding the data
+ * using the specified {@link Charset}.
+ *
+ * <p><b>Note:</b> This class should only be used if it is necessary to
+ * redirect an {@link OutputStream} to a {@link Writer} for compatibility
+ * purposes. It is much more efficient to write to the {@link Writer}
+ * directly.</p>
+ */
+public class WriterOutputStream extends OutputStream {
+
+    private final Writer out;
+    private final CharsetDecoder decoder;
+    private final ByteBuffer decoderIn = ByteBuffer.allocate(256);
+    private final CharBuffer decoderOut = CharBuffer.allocate(128);
+
+    public WriterOutputStream(Writer out, Charset charset) {
+        this(out, charset.newDecoder()
+                .onMalformedInput(CodingErrorAction.REPLACE)
+                .onUnmappableCharacter(CodingErrorAction.REPLACE));
+    }
+
+    public WriterOutputStream(Writer out, CharsetDecoder decoder) {
+        this.out = out;
+        this.decoder = decoder;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        write(new byte[] { (byte)b }, 0, 1);
+    }
+
+    @Override
+    public void write(byte[] b) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            final int c = Math.min(len, decoderIn.remaining());
+            decoderIn.put(b, off, c);
+            processInput(false);
+            len -= c;
+            off += c;
+        }
+        flush();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        flushOutput();
+        out.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        processInput(true);
+        flush();
+        out.close();
+    }
+
+    /**
+     * Decode the contents of the input ByteBuffer into a CharBuffer.
+     *
+     * @param endOfInput indicates end of input
+     * @throws IOException if an I/O error occurs
+     */
+    private void processInput(final boolean endOfInput) throws IOException {
+        // Prepare decoderIn for reading
+        decoderIn.flip();
+        CoderResult coderResult;
+        while (true) {
+            coderResult = decoder.decode(decoderIn, decoderOut, endOfInput);
+            if (coderResult.isOverflow()) {
+                flushOutput();
+            } else if (coderResult.isUnderflow()) {
+                break;
+            } else {
+                // The decoder is configured to replace malformed input and unmappable characters,
+                // so we should not get here.
+                throw new IOException("Unexpected coder result");
+            }
+        }
+        // Discard the bytes that have been read
+        decoderIn.compact();
+    }
+
+    /**
+     * Flush the output.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    private void flushOutput() throws IOException {
+        if (decoderOut.position() > 0) {
+            out.write(decoderOut.array(), 0, decoderOut.position());
+            decoderOut.rewind();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ansi.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,23 @@
+#	Reconstructed via infocmp from file: /usr/share/terminfo/61/ansi
+ansi|ansi/pc-term compatible with color,
+	am, mc5i, mir, msgr,
+	colors#8, cols#80, it#8, lines#24, ncv#3, pairs#64,
+	acsc=+\020\,\021-\030.^Y0\333`\004a\261f\370g\361h\260j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376,
+	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, dch=\E[%p1%dP, dch1=\E[P,
+	dl=\E[%p1%dM, dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K,
+	el1=\E[1K, home=\E[H, hpa=\E[%i%p1%dG, ht=\E[I, hts=\EH,
+	ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L, ind=^J,
+	indn=\E[%p1%dS, invis=\E[8m, kbs=^H, kcbt=\E[Z, kcub1=\E[D,
+	kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, khome=\E[H, kich1=\E[L,
+	mc4=\E[4i, mc5=\E[5i, nel=\r\E[S, op=\E[39;49m,
+	rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, rin=\E[%p1%dT,
+	rmacs=\E[10m, rmpch=\E[10m, rmso=\E[m, rmul=\E[m,
+	s0ds=\E(B, s1ds=\E)B, s2ds=\E*B, s3ds=\E+B,
+	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, smacs=\E[11m, smpch=\E[11m, smso=\E[7m,
+	smul=\E[4m, tbc=\E[2g, u6=\E[%i%d;%dR, u7=\E[6n,
+	u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/capabilities.txt	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,473 @@
+#
+# 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
+#
+
+auto_left_margin, bw, bw
+auto_right_margin, am, am
+back_color_erase, bce, ut
+can_change, ccc, cc
+ceol_standout_glitch, xhp, xs
+col_addr_glitch, xhpa, YA
+cpi_changes_res, cpix, YF
+cr_cancels_micro_mode, crxm, YB
+dest_tabs_magic_smso, xt, xt
+eat_newline_glitch, xenl, xn
+erase_overstrike, eo, eo
+generic_type, gn, gn
+hard_copy, hc, hc
+hard_cursor, chts, HC
+has_meta_key, km, km
+has_print_wheel, daisy, YC
+has_status_line, hs, hs
+hue_lightness_saturation, hls, hl
+insert_null_glitch, in, in
+lpi_changes_res, lpix, YG
+memory_above, da, da
+memory_below, db, db
+move_insert_mode, mir, mi
+move_standout_mode, msgr, ms
+needs_xon_xoff, nxon, nx
+no_esc_ctlc, xsb, xb
+no_pad_char, npc, NP
+non_dest_scroll_region, ndscr, ND
+non_rev_rmcup, nrrmc, NR
+over_strike, os, os
+prtr_silent, mc5i, 5i
+row_addr_glitch, xvpa, YD
+semi_auto_right_margin, sam, YE
+status_line_esc_ok, eslok, es
+tilde_glitch, hz, hz
+transparent_underline, ul, ul
+xon_xoff, xon, xo
+columns, cols, co
+init_tabs, it, it
+label_height, lh, lh
+label_width, lw, lw
+lines, lines, li
+lines_of_memory, lm, lm
+magic_cookie_glitch, xmc, sg
+max_attributes, ma, ma
+max_colors, colors, Co
+max_pairs, pairs, pa
+maximum_windows, wnum, MW
+no_color_video, ncv, NC
+num_labels, nlab, Nl
+padding_baud_rate, pb, pb
+virtual_terminal, vt, vt
+width_status_line, wsl, ws
+bit_image_entwining, bitwin, Yo
+bit_image_type, bitype, Yp
+buffer_capacity, bufsz, Ya
+buttons, btns, BT
+dot_horz_spacing, spinh, Yc
+dot_vert_spacing, spinv, Yb
+max_micro_address, maddr, Yd
+max_micro_jump, mjump, Ye
+micro_col_size, mcs, Yf
+micro_line_size, mls, Yg
+number_of_pins, npins, Yh
+output_res_char, orc, Yi
+output_res_horz_inch, orhi, Yk
+output_res_line, orl, Yj
+output_res_vert_inch, orvi, Yl
+print_rate, cps, Ym
+wide_char_size, widcs, Yn
+acs_chars, acsc, ac
+back_tab, cbt, bt
+bell, bel, bl
+carriage_return, cr, cr
+change_char_pitch, cpi, ZA
+change_line_pitch, lpi, ZB
+change_res_horz, chr, ZC
+change_res_vert, cvr, ZD
+change_scroll_region, csr, cs
+char_padding, rmp, rP
+clear_all_tabs, tbc, ct
+clear_margins, mgc, MC
+clear_screen, clear, cl
+clr_bol, el1, cb
+clr_eol, el, ce
+clr_eos, ed, cd
+column_address, hpa, ch
+command_character, cmdch, CC
+create_window, cwin, CW
+cursor_address, cup, cm
+cursor_down, cud1, do
+cursor_home, home, ho
+cursor_invisible, civis, vi
+cursor_left, cub1, le
+cursor_mem_address, mrcup, CM
+cursor_normal, cnorm, ve
+cursor_right, cuf1, nd
+cursor_to_ll, ll, ll
+cursor_up, cuu1, up
+cursor_visible, cvvis, vs
+define_char, defc, ZE
+delete_character, dch1, dc
+delete_line, dl1, dl
+dial_phone, dial, DI
+dis_status_line, dsl, ds
+display_clock, dclk, DK
+down_half_line, hd, hd
+ena_acs, enacs, eA
+enter_alt_charset_mode, smacs, as
+enter_am_mode, smam, SA
+enter_blink_mode, blink, mb
+enter_bold_mode, bold, md
+enter_ca_mode, smcup, ti
+enter_delete_mode, smdc, dm
+enter_dim_mode, dim, mh
+enter_doublewide_mode, swidm, ZF
+enter_draft_quality, sdrfq, ZG
+enter_insert_mode, smir, im
+enter_italics_mode, sitm, ZH
+enter_leftward_mode, slm, ZI
+enter_micro_mode, smicm, ZJ
+enter_near_letter_quality, snlq, ZK
+enter_normal_quality, snrmq, ZL
+enter_protected_mode, prot, mp
+enter_reverse_mode, rev, mr
+enter_secure_mode, invis, mk
+enter_shadow_mode, sshm, ZM
+enter_standout_mode, smso, so
+enter_subscript_mode, ssubm, ZN
+enter_superscript_mode, ssupm, ZO
+enter_underline_mode, smul, us
+enter_upward_mode, sum, ZP
+enter_xon_mode, smxon, SX
+erase_chars, ech, ec
+exit_alt_charset_mode, rmacs, ae
+exit_am_mode, rmam, RA
+exit_attribute_mode, sgr0, me
+exit_ca_mode, rmcup, te
+exit_delete_mode, rmdc, ed
+exit_doublewide_mode, rwidm, ZQ
+exit_insert_mode, rmir, ei
+exit_italics_mode, ritm, ZR
+exit_leftward_mode, rlm, ZS
+exit_micro_mode, rmicm, ZT
+exit_shadow_mode, rshm, ZU
+exit_standout_mode, rmso, se
+exit_subscript_mode, rsubm, ZV
+exit_superscript_mode, rsupm, ZW
+exit_underline_mode, rmul, ue
+exit_upward_mode, rum, ZX
+exit_xon_mode, rmxon, RX
+fixed_pause, pause, PA
+flash_hook, hook, fh
+flash_screen, flash, vb
+form_feed, ff, ff
+from_status_line, fsl, fs
+goto_window, wingo, WG
+hangup, hup, HU
+init_1string, is1, i1
+init_2string, is2, is
+init_3string, is3, i3
+init_file, if, if
+init_prog, iprog, iP
+initialize_color, initc, Ic
+initialize_pair, initp, Ip
+insert_character, ich1, ic
+insert_line, il1, al
+insert_padding, ip, ip
+key_a1, ka1, K1
+key_a3, ka3, K3
+key_b2, kb2, K2
+key_backspace, kbs, kb
+key_beg, kbeg, @1
+key_btab, kcbt, kB
+key_c1, kc1, K4
+key_c3, kc3, K5
+key_cancel, kcan, @2
+key_catab, ktbc, ka
+key_clear, kclr, kC
+key_close, kclo, @3
+key_command, kcmd, @4
+key_copy, kcpy, @5
+key_create, kcrt, @6
+key_ctab, kctab, kt
+key_dc, kdch1, kD
+key_dl, kdl1, kL
+key_down, kcud1, kd
+key_eic, krmir, kM
+key_end, kend, @7
+key_enter, kent, @8
+key_eol, kel, kE
+key_eos, ked, kS
+key_exit, kext, @9
+key_f0, kf0, k0
+key_f1, kf1, k1
+key_f10, kf10, k;
+key_f11, kf11, F1
+key_f12, kf12, F2
+key_f13, kf13, F3
+key_f14, kf14, F4
+key_f15, kf15, F5
+key_f16, kf16, F6
+key_f17, kf17, F7
+key_f18, kf18, F8
+key_f19, kf19, F9
+key_f2, kf2, k2
+key_f20, kf20, FA
+key_f21, kf21, FB
+key_f22, kf22, FC
+key_f23, kf23, FD
+key_f24, kf24, FE
+key_f25, kf25, FF
+key_f26, kf26, FG
+key_f27, kf27, FH
+key_f28, kf28, FI
+key_f29, kf29, FJ
+key_f3, kf3, k3
+key_f30, kf30, FK
+key_f31, kf31, FL
+key_f32, kf32, FM
+key_f33, kf33, FN
+key_f34, kf34, FO
+key_f35, kf35, FP
+key_f36, kf36, FQ
+key_f37, kf37, FR
+key_f38, kf38, FS
+key_f39, kf39, FT
+key_f4, kf4, k4
+key_f40, kf40, FU
+key_f41, kf41, FV
+key_f42, kf42, FW
+key_f43, kf43, FX
+key_f44, kf44, FY
+key_f45, kf45, FZ
+key_f46, kf46, Fa
+key_f47, kf47, Fb
+key_f48, kf48, Fc
+key_f49, kf49, Fd
+key_f5, kf5, k5
+key_f50, kf50, Fe
+key_f51, kf51, Ff
+key_f52, kf52, Fg
+key_f53, kf53, Fh
+key_f54, kf54, Fi
+key_f55, kf55, Fj
+key_f56, kf56, Fk
+key_f57, kf57, Fl
+key_f58, kf58, Fm
+key_f59, kf59, Fn
+key_f6, kf6, k6
+key_f60, kf60, Fo
+key_f61, kf61, Fp
+key_f62, kf62, Fq
+key_f63, kf63, Fr
+key_f7, kf7, k7
+key_f8, kf8, k8
+key_f9, kf9, k9
+key_find, kfnd, @0
+key_help, khlp, %1
+key_home, khome, kh
+key_ic, kich1, kI
+key_il, kil1, kA
+key_left, kcub1, kl
+key_ll, kll, kH
+key_mark, kmrk, %2
+key_message, kmsg, %3
+key_move, kmov, %4
+key_next, knxt, %5
+key_npage, knp, kN
+key_open, kopn, %6
+key_options, kopt, %7
+key_ppage, kpp, kP
+key_previous, kprv, %8
+key_print, kprt, %9
+key_redo, krdo, %0
+key_reference, kref, &1
+key_refresh, krfr, &2
+key_replace, krpl, &3
+key_restart, krst, &4
+key_resume, kres, &5
+key_right, kcuf1, kr
+key_save, ksav, &6
+key_sbeg, kBEG, &9
+key_scancel, kCAN, &0
+key_scommand, kCMD, *1
+key_scopy, kCPY, *2
+key_screate, kCRT, *3
+key_sdc, kDC, *4
+key_sdl, kDL, *5
+key_select, kslt, *6
+key_send, kEND, *7
+key_seol, kEOL, *8
+key_sexit, kEXT, *9
+key_sf, kind, kF
+key_sfind, kFND, *0
+key_shelp, kHLP, #1
+key_shome, kHOM, #2
+key_sic, kIC, #3
+key_sleft, kLFT, #4
+key_smessage, kMSG, %a
+key_smove, kMOV, %b
+key_snext, kNXT, %c
+key_soptions, kOPT, %d
+key_sprevious, kPRV, %e
+key_sprint, kPRT, %f
+key_sr, kri, kR
+key_sredo, kRDO, %g
+key_sreplace, kRPL, %h
+key_sright, kRIT, %i
+key_srsume, kRES, %j
+key_ssave, kSAV, !1
+key_ssuspend, kSPD, !2
+key_stab, khts, kT
+key_sundo, kUND, !3
+key_suspend, kspd, &7
+key_undo, kund, &8
+key_up, kcuu1, ku
+keypad_local, rmkx, ke
+keypad_xmit, smkx, ks
+lab_f0, lf0, l0
+lab_f1, lf1, l1
+lab_f10, lf10, la
+lab_f2, lf2, l2
+lab_f3, lf3, l3
+lab_f4, lf4, l4
+lab_f5, lf5, l5
+lab_f6, lf6, l6
+lab_f7, lf7, l7
+lab_f8, lf8, l8
+lab_f9, lf9, l9
+label_format, fln, Lf
+label_off, rmln, LF
+label_on, smln, LO
+meta_off, rmm, mo
+meta_on, smm, mm
+micro_column_address, mhpa, ZY
+micro_down, mcud1, ZZ
+micro_left, mcub1, Za
+micro_right, mcuf1, Zb
+micro_row_address, mvpa, Zc
+micro_up, mcuu1, Zd
+newline, nel, nw
+order_of_pins, porder, Ze
+orig_colors, oc, oc
+orig_pair, op, op
+pad_char, pad, pc
+parm_dch, dch, DC
+parm_delete_line, dl, DL
+parm_down_cursor, cud, DO
+parm_down_micro, mcud, Zf
+parm_ich, ich, IC
+parm_index, indn, SF
+parm_insert_line, il, AL
+parm_left_cursor, cub, LE
+parm_left_micro, mcub, Zg
+parm_right_cursor, cuf, RI
+parm_right_micro, mcuf, Zh
+parm_rindex, rin, SR
+parm_up_cursor, cuu, UP
+parm_up_micro, mcuu, Zi
+pkey_key, pfkey, pk
+pkey_local, pfloc, pl
+pkey_xmit, pfx, px
+plab_norm, pln, pn
+print_screen, mc0, ps
+prtr_non, mc5p, pO
+prtr_off, mc4, pf
+prtr_on, mc5, po
+pulse, pulse, PU
+quick_dial, qdial, QD
+remove_clock, rmclk, RC
+repeat_char, rep, rp
+req_for_input, rfi, RF
+reset_1string, rs1, r1
+reset_2string, rs2, r2
+reset_3string, rs3, r3
+reset_file, rf, rf
+restore_cursor, rc, rc
+row_address, vpa, cv
+save_cursor, sc, sc
+scroll_forward, ind, sf
+scroll_reverse, ri, sr
+select_char_set, scs, Zj
+set_attributes, sgr, sa
+set_background, setb, Sb
+set_bottom_margin, smgb, Zk
+set_bottom_margin_parm, smgbp, Zl
+set_clock, sclk, SC
+set_color_pair, scp, sp
+set_foreground, setf, Sf
+set_left_margin, smgl, ML
+set_left_margin_parm, smglp, Zm
+set_right_margin, smgr, MR
+set_right_margin_parm, smgrp, Zn
+set_tab, hts, st
+set_top_margin, smgt, Zo
+set_top_margin_parm, smgtp, Zp
+set_window, wind, wi
+start_bit_image, sbim, Zq
+start_char_set_def, scsd, Zr
+stop_bit_image, rbim, Zs
+stop_char_set_def, rcsd, Zt
+subscript_characters, subcs, Zu
+superscript_characters, supcs, Zv
+tab, ht, ta
+these_cause_cr, docr, Zw
+to_status_line, tsl, ts
+tone, tone, TO
+underline_char, uc, uc
+up_half_line, hu, hu
+user0, u0, u0
+user1, u1, u1
+user2, u2, u2
+user3, u3, u3
+user4, u4, u4
+user5, u5, u5
+user6, u6, u6
+user7, u7, u7
+user8, u8, u8
+user9, u9, u9
+wait_tone, wait, WA
+xoff_character, xoffc, XF
+xon_character, xonc, XN
+zero_motion, zerom, Zx
+alt_scancode_esc, scesa, S8
+bit_image_carriage_return, bicr, Yv
+bit_image_newline, binel, Zz
+bit_image_repeat, birep, Xy
+char_set_names, csnm, Zy
+code_set_init, csin, ci
+color_names, colornm, Yw
+define_bit_image_region, defbi, Yx
+device_type, devt, dv
+display_pc_char, dispc, S1
+end_bit_image_region, endbi, Yy
+enter_pc_charset_mode, smpch, S2
+enter_scancode_mode, smsc, S4
+exit_pc_charset_mode, rmpch, S3
+exit_scancode_mode, rmsc, S5
+get_mouse, getm, Gm
+key_mouse, kmous, Km
+mouse_info, minfo, Mi
+pc_term_options, pctrm, S6
+pkey_plab, pfxl, xl
+req_mouse_pos, reqmp, RQ
+scancode_escape, scesc, S7
+set0_des_seq, s0ds, s0
+set1_des_seq, s1ds, s1
+set2_des_seq, s2ds, s2
+set3_des_seq, s3ds, s3
+set_a_background, setab, AB
+set_a_foreground, setaf, AF
+set_color_band, setcolor, Yz
+set_lr_margin, smglr, ML
+set_page_length, slines, YZ
+set_tb_margin, smgtb, MT
+enter_horizontal_hl_mode, ehhlm, Xh
+enter_left_hl_mode, elhlm, Xl
+enter_low_hl_mode, elohlm, Xo
+enter_right_hl_mode, erhlm, Xr
+enter_top_hl_mode, ethlm, Xt
+enter_vertical_hl_mode, evhlm, Xv
+set_a_attributes, sgr1, sA
+set_pglen_inch, slength, sL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/colors.txt	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,265 @@
+#
+# 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.
+#
+# http://www.opensource.org/licenses/bsd-license.php
+#
+
+black
+maroon
+green
+olive
+navy
+purple
+teal
+silver
+grey
+red
+lime
+yellow
+blue
+fuchsia
+aqua
+white
+grey0
+navyblue
+darkblue
+blue3
+blue3a
+blue1
+darkgreen
+deepskyblue4
+deepskyblue4a
+deepskyblue4b
+dodgerblue3
+dodgerblue2
+green4
+springgreen4
+turquoise4
+deepskyblue3
+deepskyblue3a
+dodgerblue1
+green3
+springgreen3
+darkcyan
+lightseagreen
+deepskyblue2
+deepskyblue1
+green3a
+springgreen3a
+springgreen2
+cyan3
+darkturquoise
+turquoise2
+green1
+springgreen2a
+springgreen1
+mediumspringgreen
+cyan2
+cyan1
+darkred
+deeppink4
+purple4
+purple4a
+purple3
+blueviolet
+orange4
+grey37
+mediumpurple4
+slateblue3
+slateblue3a
+royalblue1
+chartreuse4
+darkseagreen4
+paleturquoise4
+steelblue
+steelblue3
+cornflowerblue
+chartreuse3
+darkseagreen4a
+cadetblue
+cadetbluea
+skyblue3
+steelblue1
+chartreuse3a
+palegreen3
+seagreen3
+aquamarine3
+mediumturquoise
+steelblue1a
+chartreuse2
+seagreen2
+seagreen1
+seagreen1a
+aquamarine1
+darkslategray2
+darkreda
+deeppink4a
+darkmagenta
+darkmagentaa
+darkviolet
+purplea
+orange4a
+lightpink4
+plum4
+mediumpurple3
+mediumpurple3a
+slateblue1
+yellow4
+wheat4
+grey53
+lightslategrey
+mediumpurple
+lightslateblue
+yellow4a
+darkolivegreen3
+darkseagreen
+lightskyblue3
+lightskyblue3a
+skyblue2
+chartreuse2a
+darkolivegreen3a
+palegreen3a
+darkseagreen3
+darkslategray3
+skyblue1
+chartreuse1
+lightgreen
+lightgreena
+palegreen1
+aquamarine1a
+darkslategray1
+red3
+deeppink4b
+mediumvioletred
+magenta3
+darkvioleta
+purpleb
+darkorange3
+indianred
+hotpink3
+mediumorchid3
+mediumorchid
+mediumpurple2
+darkgoldenrod
+lightsalmon3
+rosybrown
+grey63
+mediumpurple2a
+mediumpurple1
+gold3
+darkkhaki
+navajowhite3
+grey69
+lightsteelblue3
+lightsteelblue
+yellow3
+darkolivegreen3b
+darkseagreen3a
+darkseagreen2
+lightcyan3
+lightskyblue1
+greenyellow
+darkolivegreen2
+palegreen1a
+darkseagreen2a
+darkseagreen1
+paleturquoise1
+red3a
+deeppink3
+deeppink3a
+magenta3a
+magenta3b
+magenta2
+darkorange3a
+indianreda
+hotpink3a
+hotpink2
+orchid
+mediumorchid1
+orange3
+lightsalmon3a
+lightpink3
+pink3
+plum3
+violet
+gold3a
+lightgoldenrod3
+tan
+mistyrose3
+thistle3
+plum2
+yellow3a
+khaki3
+lightgoldenrod2
+lightyellow3
+grey84
+lightsteelblue1
+yellow2
+darkolivegreen1
+darkolivegreen1a
+darkseagreen1a
+honeydew2
+lightcyan1
+red1
+deeppink2
+deeppink1
+deeppink1a
+magenta2a
+magenta1
+orangered1
+indianred1
+indianred1a
+hotpink
+hotpinka
+mediumorchid1a
+darkorange
+salmon1
+lightcoral
+palevioletred1
+orchid2
+orchid1
+orange1
+sandybrown
+lightsalmon1
+lightpink1
+pink1
+plum1
+gold1
+lightgoldenrod2a
+lightgoldenrod2b
+navajowhite1
+mistyrose1
+thistle1
+yellow1
+lightgoldenrod1
+khaki1
+wheat1
+cornsilk1
+grey100
+grey3
+grey7
+grey11
+grey15
+grey19
+grey23
+grey27
+grey30
+grey35
+grey39
+grey42
+grey46
+grey50
+grey54
+grey58
+grey62
+grey66
+grey70
+grey74
+grey78
+grey82
+grey85
+grey89
+grey93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/dumb.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,5 @@
+#      Reconstructed via infocmp from file: /usr/share/terminfo/64/dumb
+dumb|80-column dumb tty,
+        am,
+        cols#80,
+        bel=^G, cr=^M, cud1=^J, ind=^J,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/package-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,14 @@
+/*
+ * 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
+ */
+/**
+ * JLine 3.
+ *
+ * @since 3.0
+ */
+package jdk.internal.org.jline.utils;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/screen-256color.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,27 @@
+#	Reconstructed via infocmp from file: /usr/share/terminfo/73/screen-256color
+screen-256color|GNU Screen with 256 colors,
+	am, km, mir, msgr, xenl,
+	colors#256, cols#80, it#8, lines#24, ncv#3, pairs#32767,
+	acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+	clear=\E[H\E[J, cnorm=\E[34h\E[?25h, cr=^M,
+	csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
+	cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
+	cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\EM,
+	cvvis=\E[34l, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
+	dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K, enacs=\E(B\E)0,
+	flash=\Eg, home=\E[H, ht=^I, hts=\EH, ich=\E[%p1%d@,
+	il=\E[%p1%dL, il1=\E[L, ind=^J, initc@, is2=\E)0, kbs=^H,
+	kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+	kdch1=\E[3~, kend=\E[4~, kf1=\EOP, kf10=\E[21~,
+	kf11=\E[23~, kf12=\E[24~, kf2=\EOQ, kf3=\EOR, kf4=\EOS,
+	kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~,
+	khome=\E[1~, kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
+	nel=\EE, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=^O,
+	rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[23m,
+	rmul=\E[24m, rs2=\Ec\E[?1000l\E[?25h, sc=\E7,
+	setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
+	setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
+	sgr=\E[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;,
+	sgr0=\E[m\017, smacs=^N, smcup=\E[?1049h, smir=\E[4h,
+	smkx=\E[?1h\E=, smso=\E[3m, smul=\E[4m, tbc=\E[3g,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/screen.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,26 @@
+#	Reconstructed via infocmp from file: /usr/share/terminfo/73/screen
+screen|VT 100/ANSI X3.64 virtual terminal,
+	am, km, mir, msgr, xenl,
+	colors#8, cols#80, it#8, lines#24, ncv#3, pairs#64,
+	acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+	clear=\E[H\E[J, cnorm=\E[34h\E[?25h, cr=^M,
+	csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
+	cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
+	cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\EM,
+	cvvis=\E[34l, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
+	dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K, enacs=\E(B\E)0,
+	flash=\Eg, home=\E[H, ht=^I, hts=\EH, ich=\E[%p1%d@,
+	il=\E[%p1%dL, il1=\E[L, ind=^J, is2=\E)0, kbs=^H, kcbt=\E[Z,
+	kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+	kdch1=\E[3~, kend=\E[4~, kf1=\EOP, kf10=\E[21~,
+	kf11=\E[23~, kf12=\E[24~, kf2=\EOQ, kf3=\EOR, kf4=\EOS,
+	kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~,
+	khome=\E[1~, kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
+	nel=\EE, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=^O,
+	rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[23m,
+	rmul=\E[24m, rs2=\Ec\E[?1000l\E[?25h, sc=\E7,
+	setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+	sgr=\E[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;,
+	sgr0=\E[m\017, smacs=^N, smcup=\E[?1049h, smir=\E[4h,
+	smkx=\E[?1h\E=, smso=\E[3m, smul=\E[4m, tbc=\E[3g,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-256color.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,27 @@
+windows-256color|windows with 256 colors terminal compatibility,
+	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~,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows-vtp.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,33 @@
+windows-vtp|windows with virtual terminal processing,
+	am, mc5i, mir, msgr,
+	colors#256, cols#80, it#8, lines#24, ncv#3, pairs#64,
+	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, clear=\E[H\E[J,
+	cr=^M, cub=\E[%p1%dD, cub1=\E[D, cud=\E[%p1%dB, cud1=\E[B,
+	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~,
+	smcup=\E[?1049h, rmcup=\E[?1049l, indn=\E[%p1%dS, rin=\E[%p1%dT,
+	ich=\E[%p1%d@, dch=\E[%p1%dP, ech=\E[%p1%dX, il=\E[%p1%dL, dl=\E[%p1%dM,
+	sc=\E7, rc=\E8, cnorm=\E[?12l\E[?25h, civis=\E[?25l, cvvis=\E[?12h\E[?25h,
+	smkx=\E[?1h\E=, rmkx=\E[?1l\E>, u6=\E[%i%d;%dR, u7=\E[6n,
+	hts=\EH, smacs=\E(0, rmacs=\E(B,
+	csr=\E[%i%p1%d;%p2%dr,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/windows.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,27 @@
+windows|windows terminal compatibility,
+	am, mc5i, mir, msgr,
+	colors#16, 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~,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/xterm-256color.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,51 @@
+#	Reconstructed via infocmp from file: /usr/share/terminfo/78/xterm-256color
+xterm-256color|xterm with 256 colors,
+	am, bce, ccc, km, mc5i, mir, msgr, npc, xenl,
+	colors#256, cols#80, it#8, lines#24, pairs#32767,
+	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+	clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M,
+	csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
+	cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
+	cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
+	cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
+	dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K,
+	flash=\E[?5h$<100/>\E[?5l, home=\E[H, hpa=\E[%i%p1%dG,
+	ht=^I, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L,
+	ind=^J, indn=\E[%p1%dS,
+	initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
+	invis=\E[8m, is2=\E[!p\E[?3;4l\E[4l\E>, kDC=\E[3;2~,
+	kEND=\E[1;2F, kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D,
+	kNXT=\E[6;2~, kPRV=\E[5;2~, kRIT=\E[1;2C, kb2=\EOE, kbs=^H,
+	kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+	kdch1=\E[3~, kend=\EOF, kent=\EOM, kf1=\EOP, kf10=\E[21~,
+	kf11=\E[23~, kf12=\E[24~, kf13=\E[1;2P, kf14=\E[1;2Q,
+	kf15=\E[1;2R, kf16=\E[1;2S, kf17=\E[15;2~, kf18=\E[17;2~,
+	kf19=\E[18;2~, kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~,
+	kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~,
+	kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S,
+	kf29=\E[15;5~, kf3=\EOR, kf30=\E[17;5~, kf31=\E[18;5~,
+	kf32=\E[19;5~, kf33=\E[20;5~, kf34=\E[21;5~,
+	kf35=\E[23;5~, kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q,
+	kf39=\E[1;6R, kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~,
+	kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~,
+	kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~,
+	kf48=\E[24;6~, kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q,
+	kf51=\E[1;3R, kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
+	kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
+	kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
+	kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
+	kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
+	kind=\E[1;2B, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
+	kri=\E[1;2A, mc0=\E[i, mc4=\E[4i, mc5=\E[5i, meml=\El,
+	memu=\Em, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM,
+	rin=\E[%p1%dT, rmacs=\E(B, rmam=\E[?7l, rmcup=\E[?1049l,
+	rmir=\E[4l, rmkx=\E[?1l\E>, rmm=\E[?1034l, rmso=\E[27m,
+	rmul=\E[24m, rs1=\Ec, rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7,
+	setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
+	setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
+	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
+	sgr0=\E(B\E[m, smacs=\E(0, smam=\E[?7h, smcup=\E[?1049h,
+	smir=\E[4h, smkx=\E[?1h\E=, smm=\E[?1034h, smso=\E[7m,
+	smul=\E[4m, tbc=\E[3g, u6=\E[%i%d;%dR, u7=\E[6n,
+	u8=\E[?1;2c, u9=\E[c, vpa=\E[%i%p1%dd,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/xterm.caps	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,51 @@
+#	Reconstructed via infocmp from file: /usr/share/terminfo/78/xterm
+xterm|xterm terminal emulator (X Window System),
+	am, bce, km, mc5i, mir, msgr, npc, xenl,
+	colors#8, cols#80, it#8, lines#24, pairs#64,
+	acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+	clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M,
+	csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
+	cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
+	cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
+	cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
+	dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K,
+	flash=\E[?5h$<100/>\E[?5l, home=\E[H, hpa=\E[%i%p1%dG,
+	ht=^I, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L,
+	ind=^J, indn=\E[%p1%dS, invis=\E[8m,
+	is2=\E[!p\E[?3;4l\E[4l\E>, kDC=\E[3;2~, kEND=\E[1;2F,
+	kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~,
+	kPRV=\E[5;2~, kRIT=\E[1;2C, kb2=\EOE, kbs=^H, kcbt=\E[Z,
+	kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+	kdch1=\E[3~, kend=\EOF, kent=\EOM, kf1=\EOP, kf10=\E[21~,
+	kf11=\E[23~, kf12=\E[24~, kf13=\E[1;2P, kf14=\E[1;2Q,
+	kf15=\E[1;2R, kf16=\E[1;2S, kf17=\E[15;2~, kf18=\E[17;2~,
+	kf19=\E[18;2~, kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~,
+	kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~,
+	kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S,
+	kf29=\E[15;5~, kf3=\EOR, kf30=\E[17;5~, kf31=\E[18;5~,
+	kf32=\E[19;5~, kf33=\E[20;5~, kf34=\E[21;5~,
+	kf35=\E[23;5~, kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q,
+	kf39=\E[1;6R, kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~,
+	kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~,
+	kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~,
+	kf48=\E[24;6~, kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q,
+	kf51=\E[1;3R, kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
+	kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
+	kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
+	kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
+	kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
+	kind=\E[1;2B, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
+	kri=\E[1;2A, mc0=\E[i, mc4=\E[4i, mc5=\E[5i, meml=\El,
+	memu=\Em, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM,
+	rin=\E[%p1%dT, rmacs=\E(B, rmam=\E[?7l, rmcup=\E[?1049l,
+	rmir=\E[4l, rmkx=\E[?1l\E>, rmm=\E[?1034l, rmso=\E[27m,
+	rmul=\E[24m, rs1=\Ec, rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7,
+	setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+	setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+	setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+	sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
+	sgr0=\E(B\E[m, smacs=\E(0, smam=\E[?7h, smcup=\E[?1049h,
+	smir=\E[4h, smkx=\E[?1h\E=, smm=\E[?1034h, smso=\E[7m,
+	smul=\E[4m, tbc=\E[3g, u6=\E[%i%d;%dR, u7=\E[6n,
+	u8=\E[?1;2c, u9=\E[c, vpa=\E[%i%p1%dd,
--- a/src/jdk.internal.le/share/classes/module-info.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.internal.le/share/classes/module-info.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,23 +29,35 @@
  * @since 9
  */
 module jdk.internal.le {
-    exports jdk.internal.jline to
+    exports jdk.internal.org.jline.keymap to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.org.jline.reader to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
-    exports jdk.internal.jline.console to
+    exports jdk.internal.org.jline.reader.impl to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
-    exports jdk.internal.jline.console.completer to
+    exports jdk.internal.org.jline.reader.impl.completer to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.org.jline.reader.impl.history to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
-    exports jdk.internal.jline.console.history to
+    exports jdk.internal.org.jline.terminal.impl to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
-    exports jdk.internal.jline.extra to
+    exports jdk.internal.org.jline.terminal to
+        jdk.scripting.nashorn.shell,
+        jdk.jshell;
+    exports jdk.internal.org.jline.utils to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
-    exports jdk.internal.jline.internal to
+    exports jdk.internal.org.jline.terminal.spi to
         jdk.scripting.nashorn.shell,
         jdk.jshell;
+
+    uses jdk.internal.org.jline.terminal.spi.JnaSupport;
+
 }
 
--- a/src/jdk.internal.le/share/legal/jline.md	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.internal.le/share/legal/jline.md	Tue Dec 11 11:29:28 2018 +0100
@@ -1,12 +1,12 @@
-## JLine v2.14.6
+## JLine v3.9.0
 
 ### JLine License
 <pre>
 
-Copyright (c) 2002-2016, the original author or authors.
+Copyright (c) 2002-2018, the original author or authors.
 All rights reserved.
 
-http://www.opensource.org/licenses/bsd-license.php
+https://opensource.org/licenses/BSD-3-Clause
 
 Redistribution and use in source and binary forms, with or
 without modification, are permitted provided that the following
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,42 @@
+package jdk.internal.org.jline.terminal.impl.jna;
+
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.impl.jna.win.JnaWinSysTerminal;
+import jdk.internal.org.jline.terminal.spi.JnaSupport;
+import jdk.internal.org.jline.terminal.spi.Pty;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.function.Function;
+
+public class JnaSupportImpl implements JnaSupport {
+    @Override
+    public Pty current() throws IOException {
+//        return JnaNativePty.current();
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Pty open(Attributes attributes, Size size) throws IOException {
+//        return JnaNativePty.open(attributes, size);
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler) throws IOException {
+        return winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, false);
+    }
+
+    @Override
+    public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException {
+        return winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, input -> input);
+    }
+
+    @Override
+    public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
+        return JnaWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, inputStreamWrapper);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/IntByReference.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+class IntByReference {
+
+    public int value;
+
+    public int getValue() {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinConsoleWriter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2017, 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
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+//import com.sun.jna.LastErrorException;
+//import com.sun.jna.Pointer;
+//import com.sun.jna.ptr.IntByReference;
+import jdk.internal.org.jline.terminal.impl.AbstractWindowsConsoleWriter;
+
+import java.io.IOException;
+
+class JnaWinConsoleWriter extends AbstractWindowsConsoleWriter {
+
+    private final Pointer consoleHandle;
+    private final IntByReference writtenChars = new IntByReference();
+
+    JnaWinConsoleWriter(Pointer consoleHandle) {
+        this.consoleHandle = consoleHandle;
+    }
+
+    @Override
+    protected void writeConsole(char[] text, int len) throws IOException {
+        try {
+            Kernel32.INSTANCE.WriteConsoleW(this.consoleHandle, text, len, this.writtenChars, null);
+        } catch (LastErrorException e) {
+            throw new IOException("Failed to write to console", e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+
+//import com.sun.jna.LastErrorException;
+//import com.sun.jna.Pointer;
+//import com.sun.jna.ptr.IntByReference;
+
+import jdk.internal.org.jline.terminal.Cursor;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
+import jdk.internal.org.jline.utils.InfoCmp;
+import jdk.internal.org.jline.utils.OSUtils;
+
+public class JnaWinSysTerminal extends AbstractWindowsTerminal {
+
+    private static final Pointer consoleIn = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_INPUT_HANDLE);
+    private static final Pointer consoleOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
+
+    public static JnaWinSysTerminal createTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, boolean paused, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
+        Writer writer;
+        if (ansiPassThrough) {
+            if (type == null) {
+                type = OSUtils.IS_CONEMU ? TYPE_WINDOWS_256_COLOR : TYPE_WINDOWS;
+            }
+            writer = new JnaWinConsoleWriter(consoleOut);
+        } else {
+            IntByReference mode = new IntByReference();
+            Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
+            try {
+                Kernel32.INSTANCE.SetConsoleMode(consoleOut, mode.getValue() | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+                if (type == null) {
+                    type = TYPE_WINDOWS_VTP;
+                }
+                writer = new JnaWinConsoleWriter(consoleOut);
+            } catch (LastErrorException e) {
+                if (OSUtils.IS_CONEMU) {
+                    if (type == null) {
+                        type = TYPE_WINDOWS_256_COLOR;
+                    }
+                    writer = new JnaWinConsoleWriter(consoleOut);
+                } else {
+                    if (type == null) {
+                        type = TYPE_WINDOWS;
+                    }
+                    writer = new WindowsAnsiWriter(new BufferedWriter(new JnaWinConsoleWriter(consoleOut)), consoleOut);
+                }
+            }
+        }
+        JnaWinSysTerminal terminal = new JnaWinSysTerminal(writer, name, type, encoding, codepage, nativeSignals, signalHandler, inputStreamWrapper);
+        // Start input pump thread
+        if (!paused) {
+            terminal.resume();
+        }
+        return terminal;
+    }
+
+    JnaWinSysTerminal(Writer writer, String name, String type, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, Function<InputStream, InputStream> inputStreamWrapper) throws IOException {
+        super(writer, name, type, encoding, codepage, nativeSignals, signalHandler, inputStreamWrapper);
+        strings.put(InfoCmp.Capability.key_mouse, "\\E[M");
+    }
+
+    @Override
+    protected int getConsoleOutputCP() {
+        return Kernel32.INSTANCE.GetConsoleOutputCP();
+    }
+
+    @Override
+    protected int getConsoleMode() {
+        IntByReference mode = new IntByReference();
+        Kernel32.INSTANCE.GetConsoleMode(consoleIn, mode);
+        return mode.getValue();
+    }
+
+    @Override
+    protected void setConsoleMode(int mode) {
+        Kernel32.INSTANCE.SetConsoleMode(consoleIn, mode);
+    }
+
+    public Size getSize() {
+        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);
+    }
+
+    protected boolean processConsoleInput() throws IOException {
+        Kernel32.INPUT_RECORD event = readConsoleInput(100);
+        if (event == null) {
+            return false;
+        }
+
+        switch (event.EventType) {
+            case Kernel32.INPUT_RECORD.KEY_EVENT:
+                processKeyEvent(event.Event.KeyEvent);
+                return true;
+            case Kernel32.INPUT_RECORD.WINDOW_BUFFER_SIZE_EVENT:
+                raise(Signal.WINCH);
+                return false;
+            case Kernel32.INPUT_RECORD.MOUSE_EVENT:
+                processMouseEvent(event.Event.MouseEvent);
+                return true;
+            case Kernel32.INPUT_RECORD.FOCUS_EVENT:
+                processFocusEvent(event.Event.FocusEvent.bSetFocus);
+                return true;
+            default:
+                // Skip event
+                return false;
+        }
+    }
+
+    private void processKeyEvent(Kernel32.KEY_EVENT_RECORD keyEvent) throws IOException {
+        processKeyEvent(keyEvent.bKeyDown, keyEvent.wVirtualKeyCode, keyEvent.uChar.UnicodeChar, keyEvent.dwControlKeyState);
+    }
+
+    private char[] focus = new char[] { '\033', '[', ' ' };
+
+    private void processFocusEvent(boolean hasFocus) throws IOException {
+        if (focusTracking) {
+            focus[2] = hasFocus ? 'I' : 'O';
+            slaveInputPipe.write(focus);
+        }
+    }
+
+    private char[] mouse = new char[] { '\033', '[', 'M', ' ', ' ', ' ' };
+
+    private void processMouseEvent(Kernel32.MOUSE_EVENT_RECORD mouseEvent) throws IOException {
+        int dwEventFlags = mouseEvent.dwEventFlags;
+        int dwButtonState = mouseEvent.dwButtonState;
+        if (tracking == MouseTracking.Off
+                || tracking == MouseTracking.Normal && dwEventFlags == Kernel32.MOUSE_MOVED
+                || tracking == MouseTracking.Button && dwEventFlags == Kernel32.MOUSE_MOVED && dwButtonState == 0) {
+            return;
+        }
+        int cb = 0;
+        dwEventFlags &= ~ Kernel32.DOUBLE_CLICK; // Treat double-clicks as normal
+        if (dwEventFlags == Kernel32.MOUSE_WHEELED) {
+            cb |= 64;
+            if ((dwButtonState >> 16) < 0) {
+                cb |= 1;
+            }
+        } else if (dwEventFlags == Kernel32.MOUSE_HWHEELED) {
+            return;
+        } else if ((dwButtonState & Kernel32.FROM_LEFT_1ST_BUTTON_PRESSED) != 0) {
+            cb |= 0x00;
+        } else if ((dwButtonState & Kernel32.RIGHTMOST_BUTTON_PRESSED) != 0) {
+            cb |= 0x01;
+        } else if ((dwButtonState & Kernel32.FROM_LEFT_2ND_BUTTON_PRESSED) != 0) {
+            cb |= 0x02;
+        } else {
+            cb |= 0x03;
+        }
+        int cx = mouseEvent.dwMousePosition.X;
+        int cy = mouseEvent.dwMousePosition.Y;
+        mouse[3] = (char) (' ' + cb);
+        mouse[4] = (char) (' ' + cx + 1);
+        mouse[5] = (char) (' ' + cy + 1);
+        slaveInputPipe.write(mouse);
+    }
+
+    private final Kernel32.INPUT_RECORD[] inputEvents = new Kernel32.INPUT_RECORD[1];
+    private final IntByReference eventsRead = new IntByReference();
+
+    private Kernel32.INPUT_RECORD readConsoleInput(int dwMilliseconds) throws IOException {
+        if (Kernel32.INSTANCE.WaitForSingleObject(consoleIn, dwMilliseconds) != 0) {
+            return null;
+        }
+        Kernel32.INSTANCE.ReadConsoleInput(consoleIn, inputEvents, 1, eventsRead);
+        if (eventsRead.getValue() == 1) {
+            return inputEvents[0];
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public Cursor getCursorPosition(IntConsumer discarded) {
+        Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
+        Kernel32.INSTANCE.GetConsoleScreenBufferInfo(consoleOut, info);
+        return new Cursor(info.dwCursorPosition.X, info.dwCursorPosition.Y);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Kernel32.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,633 @@
+/*
+ * 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.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+//OpenJDK changes:
+//-references to JNA types commented out
+//-replacement types provided where needed (IntByReference, LastErrorException, Pointer)
+//-methods not used by JLine commented out
+//-provided an implementation of the interface (Kernel32Impl), backed by a native implementation (Kernel32.cpp)
+
+//import com.sun.jna.LastErrorException;
+//import com.sun.jna.Native;
+//import com.sun.jna.Pointer;
+//import com.sun.jna.Structure;
+//import com.sun.jna.Union;
+//import com.sun.jna.ptr.IntByReference;
+//import com.sun.jna.win32.StdCallLibrary;
+//import com.sun.jna.win32.W32APIOptions;
+
+interface Kernel32 {//extends StdCallLibrary {
+
+    Kernel32 INSTANCE = new Kernel32Impl();
+//    Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
+
+//    Pointer INVALID_HANDLE_VALUE = Pointer.createConstant(-1L);
+
+    int STD_INPUT_HANDLE =  -10;
+    int STD_OUTPUT_HANDLE = -11;
+    int STD_ERROR_HANDLE =  -12;
+
+    int ENABLE_PROCESSED_INPUT =    0x0001;
+    int ENABLE_LINE_INPUT =         0x0002;
+    int ENABLE_ECHO_INPUT =         0x0004;
+    int ENABLE_WINDOW_INPUT =       0x0008;
+    int ENABLE_MOUSE_INPUT =        0x0010;
+    int ENABLE_INSERT_MODE =        0x0020;
+    int ENABLE_QUICK_EDIT_MODE =    0x0040;
+    int ENABLE_EXTENDED_FLAGS =     0x0080;
+
+    int RIGHT_ALT_PRESSED =     0x0001;
+    int LEFT_ALT_PRESSED =      0x0002;
+    int RIGHT_CTRL_PRESSED =    0x0004;
+    int LEFT_CTRL_PRESSED =     0x0008;
+    int SHIFT_PRESSED =         0x0010;
+
+    int FOREGROUND_BLUE =       0x0001;
+    int FOREGROUND_GREEN =      0x0002;
+    int FOREGROUND_RED =        0x0004;
+    int FOREGROUND_INTENSITY =  0x0008;
+    int BACKGROUND_BLUE =       0x0010;
+    int BACKGROUND_GREEN =      0x0020;
+    int BACKGROUND_RED =        0x0040;
+    int BACKGROUND_INTENSITY =  0x0080;
+
+    // Button state
+    int FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001;
+    int RIGHTMOST_BUTTON_PRESSED     = 0x0002;
+    int FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004;
+    int FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008;
+    int FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010;
+
+    // Event flags
+    int MOUSE_MOVED                  = 0x0001;
+    int DOUBLE_CLICK                 = 0x0002;
+    int MOUSE_WHEELED                = 0x0004;
+    int MOUSE_HWHEELED               = 0x0008;
+
+    // DWORD WINAPI WaitForSingleObject(
+    //  _In_ HANDLE hHandle,
+    //  _In_ DWORD  dwMilliseconds
+    // );
+    int WaitForSingleObject(Pointer in_hHandle, int in_dwMilliseconds);
+
+    // HANDLE WINAPI GetStdHandle(
+    // __in DWORD nStdHandle
+    // );
+    Pointer GetStdHandle(int nStdHandle);
+
+//    // BOOL WINAPI AllocConsole(void);
+//    void AllocConsole() throws LastErrorException;
+//
+//    // BOOL WINAPI FreeConsole(void);
+//    void FreeConsole() throws LastErrorException;
+//
+//    // HWND WINAPI GetConsoleWindow(void);
+//    Pointer GetConsoleWindow();
+//
+//    // UINT WINAPI GetConsoleCP(void)
+//    int GetConsoleCP();
+//
+    // UINT WINAPI GetConsoleOutputCP(void)
+    int GetConsoleOutputCP();
+
+    // BOOL WINAPI FillConsoleOutputCharacter(
+    // _In_ HANDLE hConsoleOutput,
+    // _In_ TCHAR cCharacter,
+    // _In_ DWORD nLength,
+    // _In_ COORD dwWriteCoord,
+    // _Out_ LPDWORD lpNumberOfCharsWritten);
+    void FillConsoleOutputCharacter(Pointer in_hConsoleOutput,
+                                    char in_cCharacter, int in_nLength, COORD in_dwWriteCoord,
+                                    IntByReference out_lpNumberOfCharsWritten)
+            throws LastErrorException;
+
+    // BOOL WINAPI FillConsoleOutputAttribute(
+    // _In_ HANDLE hConsoleOutput,
+    // _In_ WORD wAttribute,
+    // _In_ DWORD nLength,
+    // _In_ COORD dwWriteCoord,
+    // _Out_ LPDWORD lpNumberOfAttrsWritten);
+    void FillConsoleOutputAttribute(Pointer in_hConsoleOutput,
+                                    short in_wAttribute, int in_nLength, COORD in_dwWriteCoord,
+                                    IntByReference out_lpNumberOfAttrsWritten)
+            throws LastErrorException;
+//
+////    // BOOL WINAPI GetConsoleCursorInfo(
+////    // _In_ HANDLE hConsoleOutput,
+////    // _Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo);
+////    void GetConsoleCursorInfo(Pointer in_hConsoleOutput,
+////                              CONSOLE_CURSOR_INFO.ByReference out_lpConsoleCursorInfo)
+////            throws LastErrorException;
+//
+    // BOOL WINAPI GetConsoleMode(
+    //   _In_   HANDLE hConsoleHandle,
+    //   _Out_  LPDWORD lpMode);
+    void GetConsoleMode(
+            Pointer in_hConsoleOutput,
+            IntByReference out_lpMode)
+            throws LastErrorException;
+
+    // BOOL WINAPI GetConsoleScreenBufferInfo(
+    // _In_   HANDLE hConsoleOutput,
+    // _Out_  PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
+    void GetConsoleScreenBufferInfo(
+            Pointer in_hConsoleOutput,
+            CONSOLE_SCREEN_BUFFER_INFO out_lpConsoleScreenBufferInfo)
+            throws LastErrorException;
+//
+//    // BOOL WINAPI GetNumberOfConsoleInputEvents(
+//    // _In_ HANDLE hConsoleInput,
+//    // _Out_ LPDWORD lpcNumberOfEvents);
+//    void GetNumberOfConsoleInputEvents(Pointer in_hConsoleOutput,
+//                                       IntByReference out_lpcNumberOfEvents) throws LastErrorException;
+//
+    // BOOL WINAPI ReadConsoleInput(
+    // _In_ HANDLE hConsoleInput,
+    // _Out_ PINPUT_RECORD lpBuffer,
+    // _In_ DWORD nLength,
+    // _Out_ LPDWORD lpNumberOfEventsRead);
+    void ReadConsoleInput(Pointer in_hConsoleOutput,
+                          INPUT_RECORD[] out_lpBuffer, int in_nLength,
+                          IntByReference out_lpNumberOfEventsRead) throws LastErrorException;
+
+//    // BOOL WINAPI SetConsoleCtrlHandler(
+//    // _In_opt_  PHANDLER_ROUTINE HandlerRoutine,
+//    // _In_      BOOL Add);
+//    void SetConsoleCtrlHandler(
+//            Pointer in_opt_HandlerRoutine,
+//            boolean in_Add)
+//            throws LastErrorException;
+//
+//    // BOOL WINAPI ReadConsoleOutput(
+//    // _In_     HANDLE hConsoleOutput,
+//    // _Out_    PCHAR_INFO lpBuffer,
+//    // _In_     COORD dwBufferSize,
+//    // _In_     COORD dwBufferCoord,
+//    // _Inout_  PSMALL_RECT lpReadRegion);
+////    void ReadConsoleOutput(Pointer in_hConsoleOutput, CHAR_INFO[] out_lpBuffer,
+////                           COORD in_dwBufferSize, COORD in_dwBufferCoord,
+////                           SMALL_RECT inout_lpReadRegion) throws LastErrorException;
+////    void ReadConsoleOutputA(Pointer in_hConsoleOutput, CHAR_INFO[] out_lpBuffer,
+////                            COORD in_dwBufferSize, COORD in_dwBufferCoord,
+////                            SMALL_RECT inout_lpReadRegion) throws LastErrorException;
+//
+//    // BOOL WINAPI ReadConsoleOutputCharacter(
+//    // _In_   HANDLE hConsoleOutput,
+//    // _Out_  LPTSTR lpCharacter,
+//    // _In_   DWORD nLength,
+//    // _In_   COORD dwReadCoord,
+//    // _Out_  LPDWORD lpNumberOfCharsRead);
+//    void ReadConsoleOutputCharacter(Pointer in_hConsoleOutput,
+//                                    char[] ouy_lpCharacter, int in_nLength, COORD in_dwReadCoord,
+//                                    IntByReference out_lpNumberOfCharsRead)
+//            throws LastErrorException;
+//    void ReadConsoleOutputCharacterA(Pointer in_hConsoleOutput,
+//                                     byte[] ouy_lpCharacter, int in_nLength, COORD in_dwReadCoord,
+//                                     IntByReference out_lpNumberOfCharsRead)
+//            throws LastErrorException;
+//
+//    // BOOL WINAPI SetConsoleCursorInfo(
+//    // _In_ HANDLE hConsoleOutput,
+//    // _In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo);
+//    void SetConsoleCursorInfo(Pointer in_hConsoleOutput,
+//                              CONSOLE_CURSOR_INFO in_lpConsoleCursorInfo)
+//            throws LastErrorException;
+//
+//    // BOOL WINAPI SetConsoleCP(
+//    // _In_ UINT wCodePageID);
+//    void SetConsoleCP(int in_wCodePageID) throws LastErrorException;
+//
+//    // BOOL WINAPI SetConsoleOutputCP(
+//    // _In_ UINT wCodePageID);
+//    void SetConsoleOutputCP(int in_wCodePageID) throws LastErrorException;
+//
+    // BOOL WINAPI SetConsoleCursorPosition(
+    // _In_ HANDLE hConsoleOutput,
+    // _In_ COORD dwCursorPosition);
+    void SetConsoleCursorPosition(Pointer in_hConsoleOutput,
+                                  COORD in_dwCursorPosition) throws LastErrorException;
+
+    // BOOL WINAPI SetConsoleMode(
+    //   _In_  HANDLE hConsoleHandle,
+    //   _In_  DWORD dwMode);
+    void SetConsoleMode(
+            Pointer in_hConsoleOutput,
+            int in_dwMode) throws LastErrorException;
+
+//    // BOOL WINAPI SetConsoleScreenBufferSize(
+//    // __in HANDLE hConsoleOutput,
+//    // __in COORD dwSize
+//    // );
+//    void SetConsoleScreenBufferSize(Pointer in_hConsoleOutput,
+//                                    COORD in_dwSize) throws LastErrorException;
+//
+    // BOOL WINAPI SetConsoleTextAttribute(
+    // _In_ HANDLE hConsoleOutput,
+    // _In_ WORD   wAttributes
+    // );
+    void SetConsoleTextAttribute(Pointer in_hConsoleOutput,
+                                 short in_wAttributes)
+            throws LastErrorException;
+
+    // BOOL WINAPI SetConsoleTitle(
+    // _In_ LPCTSTR lpConsoleTitle
+    // );
+    void SetConsoleTitle(String in_lpConsoleTitle)
+            throws LastErrorException;
+
+//    // BOOL WINAPI SetConsoleWindowInfo(
+//    // _In_ HANDLE hConsoleOutput,
+//    // _In_ BOOL bAbsolute,
+//    // _In_ const SMALL_RECT *lpConsoleWindow);
+//    void SetConsoleWindowInfo(Pointer in_hConsoleOutput,
+//                              boolean in_bAbsolute, SMALL_RECT in_lpConsoleWindow)
+//            throws LastErrorException;
+
+    // BOOL WINAPI WriteConsole(
+    //  _In_             HANDLE  hConsoleOutput,
+    //  _In_       const VOID    *lpBuffer,
+    //  _In_             DWORD   nNumberOfCharsToWrite,
+    //  _Out_            LPDWORD lpNumberOfCharsWritten,
+    //  _Reserved_       LPVOID  lpReserved
+    // );
+    void WriteConsoleW(Pointer in_hConsoleOutput, char[] in_lpBuffer, int in_nNumberOfCharsToWrite,
+                          IntByReference out_lpNumberOfCharsWritten, Pointer reserved_lpReserved) throws LastErrorException;
+
+//    // BOOL WINAPI WriteConsoleOutput(
+//    // _In_ HANDLE hConsoleOutput,
+//    // _In_ const CHAR_INFO *lpBuffer,
+//    // _In_ COORD dwBufferSize,
+//    // _In_ COORD dwBufferCoord,
+//    // _Inout_ PSMALL_RECT lpWriteRegion);
+////    void WriteConsoleOutput(Pointer in_hConsoleOutput, CHAR_INFO[] in_lpBuffer,
+////                            COORD in_dwBufferSize, COORD in_dwBufferCoord,
+////                            SMALL_RECT inout_lpWriteRegion) throws LastErrorException;
+////    void WriteConsoleOutputA(Pointer in_hConsoleOutput, CHAR_INFO[] in_lpBuffer,
+////                             COORD in_dwBufferSize, COORD in_dwBufferCoord,
+////                             SMALL_RECT inout_lpWriteRegion) throws LastErrorException;
+//
+//    // BOOL WINAPI WriteConsoleOutputCharacter(
+//    // _In_ HANDLE hConsoleOutput,
+//    // _In_ LPCTSTR lpCharacter,
+//    // _In_ DWORD nLength,
+//    // _In_ COORD dwWriteCoord,
+//    // _Out_ LPDWORD lpNumberOfCharsWritten);
+//    void WriteConsoleOutputCharacter(Pointer in_hConsoleOutput,
+//                                     char[] in_lpCharacter, int in_nLength, COORD in_dwWriteCoord,
+//                                     IntByReference out_lpNumberOfCharsWritten)
+//            throws LastErrorException;
+//    void WriteConsoleOutputCharacterA(Pointer in_hConsoleOutput,
+//                                      byte[] in_lpCharacter, int in_nLength, COORD in_dwWriteCoord,
+//                                      IntByReference out_lpNumberOfCharsWritten)
+//            throws LastErrorException;
+//
+    // BOOL WINAPI ScrollConsoleScreenBuffer(
+    //     _In_           HANDLE     hConsoleOutput,
+    //     _In_     const SMALL_RECT *lpScrollRectangle,
+    //     _In_opt_ const SMALL_RECT *lpClipRectangle,
+    //     _In_           COORD      dwDestinationOrigin,
+    //     _In_     const CHAR_INFO  *lpFill);
+    void ScrollConsoleScreenBuffer(Pointer in_hConsoleOutput,
+                                   SMALL_RECT in_lpScrollRectangle,
+                                   SMALL_RECT in_lpClipRectangle,
+                                   COORD in_dwDestinationOrigin,
+                                   CHAR_INFO in_lpFill)
+            throws LastErrorException;
+
+    // typedef struct _CHAR_INFO {
+    //   union {
+    //     WCHAR UnicodeChar;
+    //     CHAR  AsciiChar;
+    //   } Char;
+    //   WORD  Attributes;
+    // } CHAR_INFO, *PCHAR_INFO;
+    class CHAR_INFO {//extends Structure {
+        public CHAR_INFO() {
+        }
+
+        public CHAR_INFO(char c, short attr) {
+            uChar = new UnionChar(c);
+            Attributes = attr;
+        }
+
+//        public CHAR_INFO(byte c, short attr) {
+//            uChar = new UnionChar(c);
+//            Attributes = attr;
+//        }
+
+        public UnionChar uChar;
+        public short Attributes;
+
+//        public static CHAR_INFO[] createArray(int size) {
+//            return (CHAR_INFO[]) new CHAR_INFO().toArray(size);
+//        }
+//
+//        private static String[] fieldOrder = { "uChar", "Attributes" };
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _CONSOLE_CURSOR_INFO {
+    //   DWORD dwSize;
+    //   BOOL  bVisible;
+    // } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
+    class CONSOLE_CURSOR_INFO {//extends Structure {
+        public int dwSize;
+        public boolean bVisible;
+
+//        public static class ByReference extends CONSOLE_CURSOR_INFO implements
+//                Structure.ByReference {
+//        }
+//
+//        private static String[] fieldOrder = { "dwSize", "bVisible" };
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
+    //   COORD      dwSize;
+    //   COORD      dwCursorPosition;
+    //   WORD       wAttributes;
+    //   SMALL_RECT srWindow;
+    //   COORD      dwMaximumWindowSize;
+    // } CONSOLE_SCREEN_BUFFER_INFO;
+    class CONSOLE_SCREEN_BUFFER_INFO {//extends Structure {
+        public COORD      dwSize;
+        public COORD      dwCursorPosition;
+        public short      wAttributes;
+        public SMALL_RECT srWindow;
+        public COORD      dwMaximumWindowSize;
+
+//        private static String[] fieldOrder = { "dwSize", "dwCursorPosition", "wAttributes", "srWindow", "dwMaximumWindowSize" };
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+
+        public int windowWidth() {
+            return this.srWindow.width() + 1;
+        }
+
+        public int windowHeight() {
+            return this.srWindow.height() + 1;
+        }
+    }
+
+    // typedef struct _COORD {
+    //    SHORT X;
+    //    SHORT Y;
+    //  } COORD, *PCOORD;
+    class COORD {//extends Structure implements Structure.ByValue {
+        public COORD() {
+        }
+
+        public COORD(short X, short Y) {
+            this.X = X;
+            this.Y = Y;
+        }
+
+        public short X;
+        public short Y;
+
+//        private static String[] fieldOrder = { "X", "Y" };
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _INPUT_RECORD {
+    //   WORD  EventType;
+    //   union {
+    //     KEY_EVENT_RECORD          KeyEvent;
+    //     MOUSE_EVENT_RECORD        MouseEvent;
+    //     WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
+    //     MENU_EVENT_RECORD         MenuEvent;
+    //     FOCUS_EVENT_RECORD        FocusEvent;
+    //   } Event;
+    // } INPUT_RECORD;
+    class INPUT_RECORD {//extends Structure {
+        public static final short KEY_EVENT = 0x0001;
+        public static final short MOUSE_EVENT = 0x0002;
+        public static final short WINDOW_BUFFER_SIZE_EVENT = 0x0004;
+        public static final short MENU_EVENT = 0x0008;
+        public static final short FOCUS_EVENT = 0x0010;
+
+        public short EventType;
+        public EventUnion Event;
+
+        public static class EventUnion {//extends Union {
+            public KEY_EVENT_RECORD KeyEvent;
+            public MOUSE_EVENT_RECORD MouseEvent;
+            public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
+            public MENU_EVENT_RECORD MenuEvent;
+            public FOCUS_EVENT_RECORD FocusEvent;
+        }
+
+//        @Override
+//        public void read() {
+//            readField("EventType");
+//            switch (EventType) {
+//                case KEY_EVENT:
+//                    Event.setType(KEY_EVENT_RECORD.class);
+//                    break;
+//                case MOUSE_EVENT:
+//                    Event.setType(MOUSE_EVENT_RECORD.class);
+//                    break;
+//                case WINDOW_BUFFER_SIZE_EVENT:
+//                    Event.setType(WINDOW_BUFFER_SIZE_RECORD.class);
+//                    break;
+//                case MENU_EVENT:
+//                    Event.setType(MENU_EVENT_RECORD.class);
+//                    break;
+//                case FOCUS_EVENT:
+//                    Event.setType(MENU_EVENT_RECORD.class);
+//                    break;
+//            }
+//            super.read();
+//        }
+
+//        private static String[] fieldOrder = {"EventType", "Event"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _KEY_EVENT_RECORD {
+    //   BOOL  bKeyDown;
+    //   WORD  wRepeatCount;
+    //   WORD  wVirtualKeyCode;
+    //   WORD  wVirtualScanCode;
+    //   union {
+    //     WCHAR UnicodeChar;
+    //     CHAR  AsciiChar;
+    //   } uChar;
+    //   DWORD dwControlKeyState;
+    // } KEY_EVENT_RECORD;
+    class KEY_EVENT_RECORD {//extends Structure {
+        public boolean bKeyDown;
+        public short wRepeatCount;
+        public short wVirtualKeyCode;
+        public short wVirtualScanCode;
+        public UnionChar uChar;
+        public int dwControlKeyState;
+
+//        private static String[] fieldOrder = {"bKeyDown", "wRepeatCount", "wVirtualKeyCode", "wVirtualScanCode", "uChar", "dwControlKeyState"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _MOUSE_EVENT_RECORD {
+    //   COORD dwMousePosition;
+    //   DWORD dwButtonState;
+    //   DWORD dwControlKeyState;
+    //   DWORD dwEventFlags;
+    // } MOUSE_EVENT_RECORD;
+    class MOUSE_EVENT_RECORD {//extends Structure {
+        public COORD dwMousePosition;
+        public int dwButtonState;
+        public int dwControlKeyState;
+        public int dwEventFlags;
+
+//        private static String[] fieldOrder = { "dwMousePosition", "dwButtonState", "dwControlKeyState", "dwEventFlags"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _WINDOW_BUFFER_SIZE_RECORD {
+    //   COORD dwSize;
+    // } WINDOW_BUFFER_SIZE_RECORD;
+    class WINDOW_BUFFER_SIZE_RECORD {//extends Structure {
+        public COORD dwSize;
+
+//        private static String[] fieldOrder = {"dwSize"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _MENU_EVENT_RECORD {
+    //   UINT dwCommandId;
+    // } MENU_EVENT_RECORD, *PMENU_EVENT_RECORD;
+    class MENU_EVENT_RECORD {//extends Structure {
+
+        public int dwCommandId;
+
+//        private static String[] fieldOrder = {"dwCommandId"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _FOCUS_EVENT_RECORD {
+    //  BOOL bSetFocus;
+    //} FOCUS_EVENT_RECORD;
+    class FOCUS_EVENT_RECORD {//extends Structure {
+        public boolean bSetFocus;
+
+//        private static String[] fieldOrder = {"bSetFocus"};
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+    }
+
+    // typedef struct _SMALL_RECT {
+    //    SHORT Left;
+    //    SHORT Top;
+    //    SHORT Right;
+    //    SHORT Bottom;
+    //  } SMALL_RECT;
+    class SMALL_RECT {//extends Structure {
+        public SMALL_RECT() {
+        }
+
+        public SMALL_RECT(SMALL_RECT org) {
+            this(org.Top, org.Left, org.Bottom, org.Right);
+        }
+
+        public SMALL_RECT(short Top, short Left, short Bottom, short Right) {
+            this.Top = Top;
+            this.Left = Left;
+            this.Bottom = Bottom;
+            this.Right = Right;
+        }
+
+        public short Left;
+        public short Top;
+        public short Right;
+        public short Bottom;
+
+//        private static String[] fieldOrder = { "Left", "Top", "Right", "Bottom" };
+//
+//        @Override
+//        protected java.util.List<String> getFieldOrder() {
+//            return java.util.Arrays.asList(fieldOrder);
+//        }
+
+        public short width() {
+            return (short)(this.Right - this.Left);
+        }
+
+        public short height() {
+            return (short)(this.Bottom - this.Top);
+        }
+
+    }
+
+    class UnionChar {//extends Union {
+        public UnionChar() {
+        }
+
+        public UnionChar(char c) {
+//            setType(char.class);
+            UnicodeChar = c;
+        }
+
+//        public UnionChar(byte c) {
+//            setType(byte.class);
+//            AsciiChar = c;
+//        }
+
+        public void set(char c) {
+//            setType(char.class);
+            UnicodeChar = c;
+        }
+
+//        public void set(byte c) {
+//            setType(byte.class);
+//            AsciiChar = c;
+//        }
+
+        public char UnicodeChar;
+//        public byte AsciiChar;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Kernel32Impl.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+import jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CHAR_INFO;
+import jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CONSOLE_SCREEN_BUFFER_INFO;
+import jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.COORD;
+import jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.INPUT_RECORD;
+import jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.SMALL_RECT;
+
+public class Kernel32Impl implements Kernel32 {
+
+    static {
+        System.loadLibrary("le");
+        initIDs();
+    }
+
+    private static native void initIDs();
+
+    @Override
+    public native int WaitForSingleObject(Pointer in_hHandle, int in_dwMilliseconds);
+
+    @Override
+    public native Pointer GetStdHandle(int nStdHandle);
+
+    @Override
+    public native int GetConsoleOutputCP();
+
+    @Override
+    public native void FillConsoleOutputCharacter(Pointer in_hConsoleOutput, char in_cCharacter, int in_nLength, COORD in_dwWriteCoord, IntByReference out_lpNumberOfCharsWritten) throws LastErrorException;
+
+    @Override
+    public native void FillConsoleOutputAttribute(Pointer in_hConsoleOutput, short in_wAttribute, int in_nLength, COORD in_dwWriteCoord, IntByReference out_lpNumberOfAttrsWritten) throws LastErrorException;
+
+    @Override
+    public native void GetConsoleMode(Pointer in_hConsoleOutput, IntByReference out_lpMode) throws LastErrorException;
+
+    @Override
+    public native void GetConsoleScreenBufferInfo(Pointer in_hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO out_lpConsoleScreenBufferInfo) throws LastErrorException;
+
+    @Override
+    public native void ReadConsoleInput(Pointer in_hConsoleOutput, INPUT_RECORD[] out_lpBuffer, int in_nLength, IntByReference out_lpNumberOfEventsRead) throws LastErrorException;
+
+    @Override
+    public native void SetConsoleCursorPosition(Pointer in_hConsoleOutput, COORD in_dwCursorPosition) throws LastErrorException;
+
+    @Override
+    public native void SetConsoleMode(Pointer in_hConsoleOutput, int in_dwMode) throws LastErrorException;
+
+    @Override
+    public native void SetConsoleTextAttribute(Pointer in_hConsoleOutput, short in_wAttributes) throws LastErrorException;
+
+    @Override
+    public native void SetConsoleTitle(String in_lpConsoleTitle) throws LastErrorException;
+
+    @Override
+    public native void WriteConsoleW(Pointer in_hConsoleOutput, char[] in_lpBuffer, int in_nNumberOfCharsToWrite, IntByReference out_lpNumberOfCharsWritten, Pointer reserved_lpReserved) throws LastErrorException;
+
+    @Override
+    public native void ScrollConsoleScreenBuffer(Pointer in_hConsoleOutput, SMALL_RECT in_lpScrollRectangle, SMALL_RECT in_lpClipRectangle, COORD in_dwDestinationOrigin, CHAR_INFO in_lpFill) throws LastErrorException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/LastErrorException.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+@SuppressWarnings("serial")
+class LastErrorException extends RuntimeException{
+
+    public final long lastError;
+
+    public LastErrorException(long lastError) {
+        this.lastError = lastError;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/Pointer.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+class Pointer {
+    public final long value;
+
+    public Pointer(long value) {
+        this.value = value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/WindowsAnsiWriter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,353 @@
+/*
+ * 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
+ */
+package jdk.internal.org.jline.terminal.impl.jna.win;
+
+import java.io.IOException;
+import java.io.Writer;
+
+//import com.sun.jna.Pointer;
+//import com.sun.jna.ptr.IntByReference;
+import jdk.internal.org.jline.utils.AnsiWriter;
+import jdk.internal.org.jline.utils.Colors;
+
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_BLUE;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_GREEN;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_INTENSITY;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.BACKGROUND_RED;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOREGROUND_BLUE;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOREGROUND_GREEN;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOREGROUND_INTENSITY;
+import static jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOREGROUND_RED;
+
+
+/**
+ * A Windows ANSI escape processor, uses JNA to access native platform
+ * API's to change the console attributes.
+ *
+ * @since 1.0
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ * @author Joris Kuipers
+ */
+public final class WindowsAnsiWriter extends AnsiWriter {
+
+    private static final short FOREGROUND_BLACK   = 0;
+    private static final short FOREGROUND_YELLOW  = (short) (FOREGROUND_RED|FOREGROUND_GREEN);
+    private static final short FOREGROUND_MAGENTA = (short) (FOREGROUND_BLUE|FOREGROUND_RED);
+    private static final short FOREGROUND_CYAN    = (short) (FOREGROUND_BLUE|FOREGROUND_GREEN);
+    private static final short FOREGROUND_WHITE   = (short) (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
+
+    private static final short BACKGROUND_BLACK   = 0;
+    private static final short BACKGROUND_YELLOW  = (short) (BACKGROUND_RED|BACKGROUND_GREEN);
+    private static final short BACKGROUND_MAGENTA = (short) (BACKGROUND_BLUE|BACKGROUND_RED);
+    private static final short BACKGROUND_CYAN    = (short) (BACKGROUND_BLUE|BACKGROUND_GREEN);
+    private static final short BACKGROUND_WHITE   = (short) (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
+
+    private static final short ANSI_FOREGROUND_COLOR_MAP[] = {
+            FOREGROUND_BLACK,
+            FOREGROUND_RED,
+            FOREGROUND_GREEN,
+            FOREGROUND_YELLOW,
+            FOREGROUND_BLUE,
+            FOREGROUND_MAGENTA,
+            FOREGROUND_CYAN,
+            FOREGROUND_WHITE,
+    };
+
+    private static final short ANSI_BACKGROUND_COLOR_MAP[] = {
+            BACKGROUND_BLACK,
+            BACKGROUND_RED,
+            BACKGROUND_GREEN,
+            BACKGROUND_YELLOW,
+            BACKGROUND_BLUE,
+            BACKGROUND_MAGENTA,
+            BACKGROUND_CYAN,
+            BACKGROUND_WHITE,
+    };
+
+    private final static int MAX_ESCAPE_SEQUENCE_LENGTH = 100;
+
+    private final Pointer console;
+
+    private final Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
+    private final short originalColors;
+
+    private boolean negative;
+    private boolean bold;
+    private boolean underline;
+    private short savedX = -1;
+    private short savedY = -1;
+
+    public WindowsAnsiWriter(Writer out, Pointer console) throws IOException {
+        super(out);
+        this.console = console;
+        getConsoleInfo();
+        originalColors = info.wAttributes;
+    }
+
+    private void getConsoleInfo() throws IOException {
+        out.flush();
+        Kernel32.INSTANCE.GetConsoleScreenBufferInfo(console, info);
+        if( negative ) {
+            info.wAttributes = invertAttributeColors(info.wAttributes);
+        }
+    }
+
+    private void applyAttribute() throws IOException {
+        out.flush();
+        short attributes = info.wAttributes;
+        // bold is simulated by high foreground intensity
+        if (bold) {
+            attributes |= FOREGROUND_INTENSITY;
+        }
+        // underline is simulated by high foreground intensity
+        if (underline) {
+            attributes |= BACKGROUND_INTENSITY;
+        }
+        if( negative ) {
+            attributes = invertAttributeColors(attributes);
+        }
+        Kernel32.INSTANCE.SetConsoleTextAttribute(console, attributes);
+    }
+
+    private short invertAttributeColors(short attributes) {
+        // Swap the the Foreground and Background bits.
+        int fg = 0x000F & attributes;
+        fg <<= 4;
+        int bg = 0X00F0 & attributes;
+        bg >>= 4;
+        attributes = (short) ((attributes & 0xFF00) | fg | bg);
+        return attributes;
+    }
+
+    private void applyCursorPosition() throws IOException {
+        info.dwCursorPosition.X = (short) Math.max(0, Math.min(info.dwSize.X - 1, info.dwCursorPosition.X));
+        info.dwCursorPosition.Y = (short) Math.max(0, Math.min(info.dwSize.Y - 1, info.dwCursorPosition.Y));
+        Kernel32.INSTANCE.SetConsoleCursorPosition(console, info.dwCursorPosition);
+    }
+
+    protected void processEraseScreen(int eraseOption) throws IOException {
+        getConsoleInfo();
+        IntByReference written = new IntByReference();
+        switch(eraseOption) {
+            case ERASE_SCREEN:
+                Kernel32.COORD topLeft = new Kernel32.COORD();
+                topLeft.X = 0;
+                topLeft.Y = info.srWindow.Top;
+                int screenLength = info.srWindow.height() * info.dwSize.X;
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', screenLength, topLeft, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, screenLength, topLeft, written);
+                break;
+            case ERASE_SCREEN_TO_BEGINING:
+                Kernel32.COORD topLeft2 = new Kernel32.COORD();
+                topLeft2.X = 0;
+                topLeft2.Y = info.srWindow.Top;
+                int lengthToCursor = (info.dwCursorPosition.Y - info.srWindow.Top) * info.dwSize.X + info.dwCursorPosition.X;
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', lengthToCursor, topLeft2, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, lengthToCursor, topLeft2, written);
+                break;
+            case ERASE_SCREEN_TO_END:
+                int lengthToEnd = (info.srWindow.Bottom - info.dwCursorPosition.Y) * info.dwSize.X +
+                        (info.dwSize.X - info.dwCursorPosition.X);
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', lengthToEnd, info.dwCursorPosition, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, lengthToEnd, info.dwCursorPosition, written);
+        }
+    }
+
+    protected void processEraseLine(int eraseOption) throws IOException {
+        getConsoleInfo();
+        IntByReference written = new IntByReference();
+        switch(eraseOption) {
+            case ERASE_LINE:
+                Kernel32.COORD leftColCurrRow = new Kernel32.COORD((short) 0, info.dwCursorPosition.Y);
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', info.dwSize.X, leftColCurrRow, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, info.dwSize.X, leftColCurrRow, written);
+                break;
+            case ERASE_LINE_TO_BEGINING:
+                Kernel32.COORD leftColCurrRow2 = new Kernel32.COORD((short) 0, info.dwCursorPosition.Y);
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', info.dwCursorPosition.X, leftColCurrRow2, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, info.dwCursorPosition.X, leftColCurrRow2, written);
+                break;
+            case ERASE_LINE_TO_END:
+                int lengthToLastCol = info.dwSize.X - info.dwCursorPosition.X;
+                Kernel32.INSTANCE.FillConsoleOutputCharacter(console, ' ', lengthToLastCol, info.dwCursorPosition, written);
+                Kernel32.INSTANCE.FillConsoleOutputAttribute(console, info.wAttributes, lengthToLastCol, info.dwCursorPosition, written);
+        }
+    }
+
+    protected void processCursorUpLine(int count) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.X = 0;
+        info.dwCursorPosition.Y -= count;
+        applyCursorPosition();
+    }
+
+    protected void processCursorDownLine(int count) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.X = 0;
+        info.dwCursorPosition.Y += count;
+        applyCursorPosition();
+    }
+
+    protected void processCursorLeft(int count) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.X -= count;
+        applyCursorPosition();
+    }
+
+    protected void processCursorRight(int count) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.X += count;
+        applyCursorPosition();
+    }
+
+    protected void processCursorDown(int count) throws IOException {
+        getConsoleInfo();
+        int nb = Math.max(0, info.dwCursorPosition.Y + count - info.dwSize.Y + 1);
+        if (nb != count) {
+            info.dwCursorPosition.Y += count;
+            applyCursorPosition();
+        }
+        if (nb > 0) {
+            Kernel32.SMALL_RECT scroll = new Kernel32.SMALL_RECT(info.srWindow);
+            scroll.Top = 0;
+            Kernel32.COORD org = new Kernel32.COORD();
+            org.X = 0;
+            org.Y = (short)(- nb);
+            Kernel32.CHAR_INFO info = new Kernel32.CHAR_INFO(' ', originalColors);
+            Kernel32.INSTANCE.ScrollConsoleScreenBuffer(console, scroll, scroll, org, info);
+        }
+    }
+
+    protected void processCursorUp(int count) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.Y -= count;
+        applyCursorPosition();
+    }
+
+    protected void processCursorTo(int row, int col) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.Y = (short) (info.srWindow.Top + row - 1);
+        info.dwCursorPosition.X = (short) (col - 1);
+        applyCursorPosition();
+    }
+
+    protected void processCursorToColumn(int x) throws IOException {
+        getConsoleInfo();
+        info.dwCursorPosition.X = (short) (x - 1);
+        applyCursorPosition();
+    }
+
+    @Override
+    protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
+        int color = Colors.roundColor(paletteIndex, 16);
+        info.wAttributes = (short) ((info.wAttributes & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color & 0x07]);
+        info.wAttributes = (short) ((info.wAttributes & ~FOREGROUND_INTENSITY) | (color >= 8 ? FOREGROUND_INTENSITY : 0));
+        applyAttribute();
+    }
+
+    protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
+        int color = Colors.roundColor(paletteIndex, 16);
+        info.wAttributes = (short)((info.wAttributes & ~0x0070 ) | ANSI_BACKGROUND_COLOR_MAP[color & 0x07]);
+        info.wAttributes = (short) ((info.wAttributes & ~BACKGROUND_INTENSITY) | (color >= 8 ? BACKGROUND_INTENSITY : 0));
+        applyAttribute();
+    }
+
+    protected void processDefaultTextColor() throws IOException {
+        info.wAttributes = (short)((info.wAttributes & ~0x000F ) | (originalColors & 0x000F));
+        applyAttribute();
+    }
+
+    protected void processDefaultBackgroundColor() throws IOException {
+        info.wAttributes = (short)((info.wAttributes & ~0x00F0 ) | (originalColors & 0x00F0));
+        applyAttribute();
+    }
+
+    protected void processAttributeRest() throws IOException {
+        info.wAttributes = (short)((info.wAttributes & ~0x00FF ) | originalColors);
+        this.negative = false;
+        this.bold = false;
+        this.underline = false;
+        applyAttribute();
+    }
+
+    protected void processSetAttribute(int attribute) throws IOException {
+        switch(attribute) {
+            case ATTRIBUTE_INTENSITY_BOLD:
+                bold = true;
+                applyAttribute();
+                break;
+            case ATTRIBUTE_INTENSITY_NORMAL:
+                bold = false;
+                applyAttribute();
+                break;
+
+            case ATTRIBUTE_UNDERLINE:
+                underline = true;
+                applyAttribute();
+                break;
+            case ATTRIBUTE_UNDERLINE_OFF:
+                underline = false;
+                applyAttribute();
+                break;
+
+            case ATTRIBUTE_NEGATIVE_ON:
+                negative = true;
+                applyAttribute();
+                break;
+            case ATTRIBUTE_NEGATIVE_OFF:
+                negative = false;
+                applyAttribute();
+                break;
+        }
+    }
+
+    protected void processSaveCursorPosition() throws IOException {
+        getConsoleInfo();
+        savedX = info.dwCursorPosition.X;
+        savedY = info.dwCursorPosition.Y;
+    }
+
+    protected void processRestoreCursorPosition() throws IOException {
+        // restore only if there was a save operation first
+        if (savedX != -1 && savedY != -1) {
+            out.flush();
+            info.dwCursorPosition.X = savedX;
+            info.dwCursorPosition.Y = savedY;
+            applyCursorPosition();
+        }
+    }
+
+    @Override
+    protected void processInsertLine(int optionInt) throws IOException {
+        getConsoleInfo();
+        Kernel32.SMALL_RECT scroll = new Kernel32.SMALL_RECT(info.srWindow);
+        scroll.Top = info.dwCursorPosition.Y;
+        Kernel32.COORD org = new Kernel32.COORD();
+        org.X = 0;
+        org.Y = (short)(info.dwCursorPosition.Y + optionInt);
+        Kernel32.CHAR_INFO info = new Kernel32.CHAR_INFO(' ', originalColors);
+        Kernel32.INSTANCE.ScrollConsoleScreenBuffer(console, scroll, scroll, org, info);
+    }
+
+    @Override
+    protected void processDeleteLine(int optionInt) throws IOException {
+        getConsoleInfo();
+        Kernel32.SMALL_RECT scroll = new Kernel32.SMALL_RECT(info.srWindow);
+        scroll.Top = info.dwCursorPosition.Y;
+        Kernel32.COORD org = new Kernel32.COORD();
+        org.X = 0;
+        org.Y = (short)(info.dwCursorPosition.Y - optionInt);
+        Kernel32.CHAR_INFO info = new Kernel32.CHAR_INFO(' ', originalColors);
+        Kernel32.INSTANCE.ScrollConsoleScreenBuffer(console, scroll, scroll, org, info);
+    }
+
+    protected void processChangeWindowTitle(String label) {
+        Kernel32.INSTANCE.SetConsoleTitle(label);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/classes/module-info.java.extra	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+provides jdk.internal.org.jline.terminal.spi.JnaSupport with jdk.internal.org.jline.terminal.impl.jna.JnaSupportImpl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/windows/native/lible/Kernel32.cpp	Tue Dec 11 11:29:28 2018 +0100
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl.h"
+
+#include <stdlib.h>
+#include <wincon.h>
+#include <winuser.h>
+
+static jclass pointerClass;
+static jmethodID pointerConstructor;
+static jfieldID pointerValue;
+
+static jclass intByReferenceClass;
+static jfieldID intByReferenceValue;
+
+static jclass lastErrorExceptionClass;
+static jmethodID lastErrorExceptionConstructor;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CHAR_INFO
+static jclass CHAR_INFO_Class;
+static jmethodID CHAR_INFO_Constructor;
+static jfieldID CHAR_INFO_uChar;
+static jfieldID CHAR_INFO_Attributes;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CONSOLE_CURSOR_INFO
+static jclass CONSOLE_CURSOR_INFO_Class;
+static jmethodID CONSOLE_CURSOR_INFO_Constructor;
+static jfieldID CONSOLE_CURSOR_INFO_dwSize;
+static jfieldID CONSOLE_CURSOR_INFO_bVisible;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CONSOLE_SCREEN_BUFFER_INFO
+static jclass CONSOLE_SCREEN_BUFFER_INFO_Class;
+static jmethodID CONSOLE_SCREEN_BUFFER_INFO_Constructor;
+static jfieldID CONSOLE_SCREEN_BUFFER_INFO_dwSize;
+static jfieldID CONSOLE_SCREEN_BUFFER_INFO_dwCursorPosition;
+static jfieldID CONSOLE_SCREEN_BUFFER_INFO_wAttributes;
+static jfieldID CONSOLE_SCREEN_BUFFER_INFO_srWindow;
+static jfieldID CONSOLE_SCREEN_BUFFER_INFO_dwMaximumWindowSize;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.COORD
+static jclass COORD_Class;
+static jmethodID COORD_Constructor;
+static jfieldID COORD_X;
+static jfieldID COORD_Y;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.INPUT_RECORD
+static jclass INPUT_RECORD_Class;
+static jmethodID INPUT_RECORD_Constructor;
+static jfieldID INPUT_RECORD_EventType;
+static jfieldID INPUT_RECORD_Event;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.INPUT_RECORD.EventUnion
+static jclass EventUnion_Class;
+static jmethodID EventUnion_Constructor;
+static jfieldID EventUnion_KeyEvent;
+static jfieldID EventUnion_MouseEvent;
+static jfieldID EventUnion_WindowBufferSizeEvent;
+static jfieldID EventUnion_MenuEvent;
+static jfieldID EventUnion_FocusEvent;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.KEY_EVENT_RECORD
+static jclass KEY_EVENT_RECORD_Class;
+static jmethodID KEY_EVENT_RECORD_Constructor;
+static jfieldID KEY_EVENT_RECORD_bKeyDown;
+static jfieldID KEY_EVENT_RECORD_wRepeatCount;
+static jfieldID KEY_EVENT_RECORD_wVirtualKeyCode;
+static jfieldID KEY_EVENT_RECORD_wVirtualScanCode;
+static jfieldID KEY_EVENT_RECORD_uChar;
+static jfieldID KEY_EVENT_RECORD_dwControlKeyState;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.MOUSE_EVENT_RECORD
+static jclass MOUSE_EVENT_RECORD_Class;
+static jmethodID MOUSE_EVENT_RECORD_Constructor;
+static jfieldID MOUSE_EVENT_RECORD_dwMousePosition;
+static jfieldID MOUSE_EVENT_RECORD_dwButtonState;
+static jfieldID MOUSE_EVENT_RECORD_dwControlKeyState;
+static jfieldID MOUSE_EVENT_RECORD_dwEventFlags;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.WINDOW_BUFFER_SIZE_RECORD
+static jclass WINDOW_BUFFER_SIZE_RECORD_Class;
+static jmethodID WINDOW_BUFFER_SIZE_RECORD_Constructor;
+static jfieldID WINDOW_BUFFER_SIZE_RECORD_dwSize;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.MENU_EVENT_RECORD
+static jclass MENU_EVENT_RECORD_Class;
+static jmethodID MENU_EVENT_RECORD_Constructor;
+static jfieldID MENU_EVENT_RECORD_dwCommandId;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOCUS_EVENT_RECORD
+static jclass FOCUS_EVENT_RECORD_Class;
+static jmethodID FOCUS_EVENT_RECORD_Constructor;
+static jfieldID FOCUS_EVENT_RECORD_bSetFocus;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.SMALL_RECT
+static jclass SMALL_RECT_Class;
+static jmethodID SMALL_RECT_Constructor;
+static jfieldID SMALL_RECT_Left;
+static jfieldID SMALL_RECT_Top;
+static jfieldID SMALL_RECT_Right;
+static jfieldID SMALL_RECT_Bottom;
+
+//jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.UnionChar
+static jclass UnionChar_Class;
+static jmethodID UnionChar_Constructor;
+static jfieldID UnionChar_UnicodeChar;
+
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_initIDs
+  (JNIEnv *env, jclass) {
+    jclass cls;
+    cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Pointer");
+    CHECK_NULL(cls);
+    pointerClass = (jclass) env->NewGlobalRef(cls);
+    pointerConstructor = env->GetMethodID(cls, "<init>", "(J)V");
+    CHECK_NULL(pointerConstructor);
+    pointerValue  = env->GetFieldID(cls, "value", "J");
+    CHECK_NULL(pointerValue);
+
+    cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/LastErrorException");
+    CHECK_NULL(cls);
+    lastErrorExceptionClass = (jclass) env->NewGlobalRef(cls);
+    lastErrorExceptionConstructor = env->GetMethodID(cls, "<init>", "(J)V");
+    CHECK_NULL(lastErrorExceptionConstructor);
+
+    cls = env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/IntByReference");
+    CHECK_NULL(cls);
+    intByReferenceClass = (jclass) env->NewGlobalRef(cls);
+    intByReferenceValue = env->GetFieldID(cls, "value", "I");
+    CHECK_NULL(intByReferenceValue);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CHAR_INFO
+    CHAR_INFO_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$CHAR_INFO"));
+    CHECK_NULL(CHAR_INFO_Class);
+    CHAR_INFO_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(CHAR_INFO_Constructor);
+    CHAR_INFO_uChar = env->GetFieldID(CHAR_INFO_Class, "uChar", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$UnionChar;");
+    CHECK_NULL(CHAR_INFO_uChar);
+    CHAR_INFO_Attributes = env->GetFieldID(CHAR_INFO_Class, "Attributes", "S");
+    CHECK_NULL(CHAR_INFO_Attributes);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CONSOLE_CURSOR_INFO
+    CONSOLE_CURSOR_INFO_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$CONSOLE_CURSOR_INFO"));
+    CHECK_NULL(CONSOLE_CURSOR_INFO_Class);
+    CONSOLE_CURSOR_INFO_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(CONSOLE_CURSOR_INFO_Constructor);
+    CONSOLE_CURSOR_INFO_dwSize = env->GetFieldID(CONSOLE_CURSOR_INFO_Class, "dwSize", "I");
+    CHECK_NULL(CONSOLE_CURSOR_INFO_dwSize);
+    CONSOLE_CURSOR_INFO_bVisible = env->GetFieldID(CONSOLE_CURSOR_INFO_Class, "bVisible", "Z");
+    CHECK_NULL(CONSOLE_CURSOR_INFO_bVisible);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.CONSOLE_SCREEN_BUFFER_INFO
+    CONSOLE_SCREEN_BUFFER_INFO_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$CONSOLE_SCREEN_BUFFER_INFO"));
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_Class);
+    CONSOLE_SCREEN_BUFFER_INFO_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_Constructor);
+    CONSOLE_SCREEN_BUFFER_INFO_dwSize = env->GetFieldID(CONSOLE_SCREEN_BUFFER_INFO_Class, "dwSize", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD;");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_dwSize);
+    CONSOLE_SCREEN_BUFFER_INFO_dwCursorPosition = env->GetFieldID(CONSOLE_SCREEN_BUFFER_INFO_Class, "dwCursorPosition", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD;");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_dwCursorPosition);
+    CONSOLE_SCREEN_BUFFER_INFO_wAttributes = env->GetFieldID(CONSOLE_SCREEN_BUFFER_INFO_Class, "wAttributes", "S");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_wAttributes);
+    CONSOLE_SCREEN_BUFFER_INFO_srWindow = env->GetFieldID(CONSOLE_SCREEN_BUFFER_INFO_Class, "srWindow", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$SMALL_RECT;");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_srWindow);
+    CONSOLE_SCREEN_BUFFER_INFO_dwMaximumWindowSize = env->GetFieldID(CONSOLE_SCREEN_BUFFER_INFO_Class, "dwMaximumWindowSize", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD;");
+    CHECK_NULL(CONSOLE_SCREEN_BUFFER_INFO_dwMaximumWindowSize);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.COORD
+    COORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD"));
+    CHECK_NULL(COORD_Class);
+    COORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(COORD_Constructor);
+    COORD_X = env->GetFieldID(COORD_Class, "X", "S");
+    CHECK_NULL(COORD_X);
+    COORD_Y = env->GetFieldID(COORD_Class, "Y", "S");
+    CHECK_NULL(COORD_Y);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.INPUT_RECORD
+    INPUT_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$INPUT_RECORD"));
+    CHECK_NULL(INPUT_RECORD_Class);
+    INPUT_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(INPUT_RECORD_Constructor);
+    INPUT_RECORD_EventType = env->GetFieldID(INPUT_RECORD_Class, "EventType", "S");
+    CHECK_NULL(INPUT_RECORD_EventType);
+    INPUT_RECORD_Event = env->GetFieldID(INPUT_RECORD_Class, "Event", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$INPUT_RECORD$EventUnion;");
+    CHECK_NULL(INPUT_RECORD_Event);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.INPUT_RECORD.EventUnion
+    EventUnion_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$INPUT_RECORD$EventUnion"));
+    CHECK_NULL(EventUnion_Class);
+    EventUnion_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(EventUnion_Constructor);
+    EventUnion_KeyEvent = env->GetFieldID(EventUnion_Class, "KeyEvent", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$KEY_EVENT_RECORD;");
+    CHECK_NULL(EventUnion_KeyEvent);
+    EventUnion_MouseEvent = env->GetFieldID(EventUnion_Class, "MouseEvent", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$MOUSE_EVENT_RECORD;");
+    CHECK_NULL(EventUnion_MouseEvent);
+    EventUnion_WindowBufferSizeEvent = env->GetFieldID(EventUnion_Class, "WindowBufferSizeEvent", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$WINDOW_BUFFER_SIZE_RECORD;");
+    CHECK_NULL(EventUnion_WindowBufferSizeEvent);
+    EventUnion_MenuEvent = env->GetFieldID(EventUnion_Class, "MenuEvent", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$MENU_EVENT_RECORD;");
+    CHECK_NULL(EventUnion_MenuEvent);
+    EventUnion_FocusEvent = env->GetFieldID(EventUnion_Class, "FocusEvent", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$FOCUS_EVENT_RECORD;");
+    CHECK_NULL(EventUnion_FocusEvent);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.KEY_EVENT_RECORD
+    KEY_EVENT_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$KEY_EVENT_RECORD"));
+    CHECK_NULL(KEY_EVENT_RECORD_Class);
+    KEY_EVENT_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(KEY_EVENT_RECORD_Constructor);
+    KEY_EVENT_RECORD_bKeyDown = env->GetFieldID(KEY_EVENT_RECORD_Class, "bKeyDown", "Z");
+    CHECK_NULL(KEY_EVENT_RECORD_bKeyDown);
+    KEY_EVENT_RECORD_wRepeatCount = env->GetFieldID(KEY_EVENT_RECORD_Class, "wRepeatCount", "S");
+    CHECK_NULL(KEY_EVENT_RECORD_wRepeatCount);
+    KEY_EVENT_RECORD_wVirtualKeyCode = env->GetFieldID(KEY_EVENT_RECORD_Class, "wVirtualKeyCode", "S");
+    CHECK_NULL(KEY_EVENT_RECORD_wVirtualKeyCode);
+    KEY_EVENT_RECORD_wVirtualScanCode = env->GetFieldID(KEY_EVENT_RECORD_Class, "wVirtualScanCode", "S");
+    CHECK_NULL(KEY_EVENT_RECORD_wVirtualScanCode);
+    KEY_EVENT_RECORD_uChar = env->GetFieldID(KEY_EVENT_RECORD_Class, "uChar", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$UnionChar;");
+    CHECK_NULL(KEY_EVENT_RECORD_uChar);
+    KEY_EVENT_RECORD_dwControlKeyState = env->GetFieldID(KEY_EVENT_RECORD_Class, "dwControlKeyState", "I");
+    CHECK_NULL(KEY_EVENT_RECORD_dwControlKeyState);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.MOUSE_EVENT_RECORD
+    MOUSE_EVENT_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$MOUSE_EVENT_RECORD"));
+    CHECK_NULL(MOUSE_EVENT_RECORD_Class);
+    MOUSE_EVENT_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(MOUSE_EVENT_RECORD_Constructor);
+    MOUSE_EVENT_RECORD_dwMousePosition = env->GetFieldID(MOUSE_EVENT_RECORD_Class, "dwMousePosition", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD;");
+    CHECK_NULL(MOUSE_EVENT_RECORD_dwMousePosition);
+    MOUSE_EVENT_RECORD_dwButtonState = env->GetFieldID(MOUSE_EVENT_RECORD_Class, "dwButtonState", "I");
+    CHECK_NULL(MOUSE_EVENT_RECORD_dwButtonState);
+    MOUSE_EVENT_RECORD_dwControlKeyState = env->GetFieldID(MOUSE_EVENT_RECORD_Class, "dwControlKeyState", "I");
+    CHECK_NULL(MOUSE_EVENT_RECORD_dwControlKeyState);
+    MOUSE_EVENT_RECORD_dwEventFlags = env->GetFieldID(MOUSE_EVENT_RECORD_Class, "dwEventFlags", "I");
+    CHECK_NULL(MOUSE_EVENT_RECORD_dwEventFlags);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.WINDOW_BUFFER_SIZE_RECORD
+    WINDOW_BUFFER_SIZE_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$WINDOW_BUFFER_SIZE_RECORD"));
+    CHECK_NULL(WINDOW_BUFFER_SIZE_RECORD_Class);
+    WINDOW_BUFFER_SIZE_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(WINDOW_BUFFER_SIZE_RECORD_Constructor);
+    WINDOW_BUFFER_SIZE_RECORD_dwSize = env->GetFieldID(WINDOW_BUFFER_SIZE_RECORD_Class, "dwSize", "Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32$COORD;");
+    CHECK_NULL(WINDOW_BUFFER_SIZE_RECORD_dwSize);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.MENU_EVENT_RECORD
+    MENU_EVENT_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$MENU_EVENT_RECORD"));
+    CHECK_NULL(MENU_EVENT_RECORD_Class);
+    MENU_EVENT_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(MENU_EVENT_RECORD_Constructor);
+    MENU_EVENT_RECORD_dwCommandId = env->GetFieldID(MENU_EVENT_RECORD_Class, "dwCommandId", "I");
+    CHECK_NULL(MENU_EVENT_RECORD_dwCommandId);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.FOCUS_EVENT_RECORD
+    FOCUS_EVENT_RECORD_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$FOCUS_EVENT_RECORD"));
+    CHECK_NULL(FOCUS_EVENT_RECORD_Class);
+    FOCUS_EVENT_RECORD_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(FOCUS_EVENT_RECORD_Constructor);
+    FOCUS_EVENT_RECORD_bSetFocus = env->GetFieldID(FOCUS_EVENT_RECORD_Class, "bSetFocus", "Z");
+    CHECK_NULL(FOCUS_EVENT_RECORD_bSetFocus);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.SMALL_RECT
+    SMALL_RECT_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$SMALL_RECT"));
+    CHECK_NULL(SMALL_RECT_Class);
+    SMALL_RECT_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(SMALL_RECT_Constructor);
+    SMALL_RECT_Left = env->GetFieldID(SMALL_RECT_Class, "Left", "S");
+    CHECK_NULL(SMALL_RECT_Left);
+    SMALL_RECT_Top = env->GetFieldID(SMALL_RECT_Class, "Top", "S");
+    CHECK_NULL(SMALL_RECT_Top);
+    SMALL_RECT_Right = env->GetFieldID(SMALL_RECT_Class, "Right", "S");
+    CHECK_NULL(SMALL_RECT_Right);
+    SMALL_RECT_Bottom = env->GetFieldID(SMALL_RECT_Class, "Bottom", "S");
+    CHECK_NULL(SMALL_RECT_Bottom);
+
+    //jdk.internal.org.jline.terminal.impl.jna.win.Kernel32.UnionChar
+    UnionChar_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/org/jline/terminal/impl/jna/win/Kernel32$UnionChar"));
+    CHECK_NULL(UnionChar_Class);
+    UnionChar_Constructor = env->GetMethodID(cls, "<init>", "()V");
+    CHECK_NULL(UnionChar_Constructor);
+    UnionChar_UnicodeChar = env->GetFieldID(UnionChar_Class, "UnicodeChar", "C");
+    CHECK_NULL(UnionChar_UnicodeChar);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    WaitForSingleObject
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;I)I
+ */
+JNIEXPORT jint JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_WaitForSingleObject
+  (JNIEnv *env, jobject kernel, jobject in_hHandle, jint in_dwMilliseconds) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hHandle, pointerValue));
+    return WaitForSingleObject(h, in_dwMilliseconds);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    GetStdHandle
+ * Signature: (I)Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;
+ */
+JNIEXPORT jobject JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_GetStdHandle
+  (JNIEnv *env, jobject, jint nStdHandle) {
+    return env->NewObject(pointerClass,
+                          pointerConstructor,
+                          nStdHandle);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    GetConsoleOutputCP
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_GetConsoleOutputCP
+  (JNIEnv *, jobject) {
+    return GetConsoleOutputCP();
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    FillConsoleOutputCharacter
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;CILjdk/internal/org/jline/terminal/impl/jna/win/Kernel32/COORD;Ljdk/internal/org/jline/terminal/impl/jna/win/IntByReference;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_FillConsoleOutputCharacter
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jchar in_cCharacter, jint in_nLength, jobject in_dwWriteCoord, jobject out_lpNumberOfCharsWritten) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    DWORD written;
+    COORD coord;
+    coord.X = (SHORT) env->GetLongField(in_dwWriteCoord, COORD_X);
+    coord.Y = (SHORT) env->GetLongField(in_dwWriteCoord, COORD_Y);
+    if (!FillConsoleOutputCharacter(h, (CHAR) in_cCharacter, in_nLength, coord, &written)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+    env->SetIntField(out_lpNumberOfCharsWritten, intByReferenceValue, written);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    FillConsoleOutputAttribute
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;SILjdk/internal/org/jline/terminal/impl/jna/win/Kernel32/COORD;Ljdk/internal/org/jline/terminal/impl/jna/win/IntByReference;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_FillConsoleOutputAttribute
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jshort in_wAttribute, jint in_nLength, jobject in_dwWriteCoord, jobject out_lpNumberOfAttrsWritten) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    DWORD written;
+    COORD coord;
+    coord.X = (SHORT) env->GetLongField(in_dwWriteCoord, COORD_X);
+    coord.Y = (SHORT) env->GetLongField(in_dwWriteCoord, COORD_Y);
+    if (!FillConsoleOutputAttribute(h, in_wAttribute, in_nLength, coord, &written)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+    env->SetIntField(out_lpNumberOfAttrsWritten, intByReferenceValue, written);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    GetConsoleMode
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;Ljdk/internal/org/jline/terminal/impl/jna/win/IntByReference;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_GetConsoleMode
+  (JNIEnv *env, jobject, jobject in_hConsoleOutput, jobject out_lpMode) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    DWORD mode;
+    if (!GetConsoleMode(h, &mode)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+    env->SetIntField(out_lpMode, intByReferenceValue, mode);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    GetConsoleScreenBufferInfo
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/CONSOLE_SCREEN_BUFFER_INFO;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_GetConsoleScreenBufferInfo
+  (JNIEnv *env, jobject, jobject in_hConsoleOutput, jobject/*CONSOLE_SCREEN_BUFFER_INFO*/ out_lpConsoleScreenBufferInfo) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    CONSOLE_SCREEN_BUFFER_INFO buffer;
+    if (!GetConsoleScreenBufferInfo(h, &buffer)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+
+    jobject dwSize = env->NewObject(COORD_Class,
+                                    COORD_Constructor);
+    env->SetIntField(dwSize, COORD_X, buffer.dwSize.X);
+    env->SetIntField(dwSize, COORD_Y, buffer.dwSize.Y);
+    env->SetObjectField(out_lpConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO_dwSize, dwSize);
+
+    jobject dwCursorPosition = env->NewObject(COORD_Class,
+                                              COORD_Constructor);
+    env->SetIntField(dwCursorPosition, COORD_X, buffer.dwCursorPosition.X);
+    env->SetIntField(dwCursorPosition, COORD_Y, buffer.dwCursorPosition.Y);
+    env->SetObjectField(out_lpConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO_dwCursorPosition, dwCursorPosition);
+
+    env->SetIntField(out_lpConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO_wAttributes, buffer.wAttributes);
+
+    jobject srWindow = env->NewObject(SMALL_RECT_Class,
+                                      SMALL_RECT_Constructor);
+    env->SetIntField(srWindow, SMALL_RECT_Left, buffer.srWindow.Left);
+    env->SetIntField(srWindow, SMALL_RECT_Top, buffer.srWindow.Top);
+    env->SetIntField(srWindow, SMALL_RECT_Right, buffer.srWindow.Right);
+    env->SetIntField(srWindow, SMALL_RECT_Bottom, buffer.srWindow.Bottom);
+    env->SetObjectField(out_lpConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO_srWindow, srWindow);
+
+    jobject dwMaximumWindowSize = env->NewObject(COORD_Class,
+                                                 COORD_Constructor);
+    env->SetIntField(dwMaximumWindowSize, COORD_X, buffer.dwMaximumWindowSize.X);
+    env->SetIntField(dwMaximumWindowSize, COORD_Y, buffer.dwMaximumWindowSize.Y);
+    env->SetObjectField(out_lpConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO_dwMaximumWindowSize, dwMaximumWindowSize);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    ReadConsoleInput
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;[Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/INPUT_RECORD;ILjdk/internal/org/jline/terminal/impl/jna/win/IntByReference;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_ReadConsoleInput
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jobjectArray/*INPUT_RECORD[]*/ out_lpBuffer, jint in_nLength, jobject out_lpNumberOfEventsRead) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    INPUT_RECORD *buffer = new INPUT_RECORD[in_nLength];
+    DWORD numberOfEventsRead;
+    if (!ReadConsoleInput(h, buffer, in_nLength, &numberOfEventsRead)) {
+        delete buffer;
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+    for (unsigned int i = 0; i < numberOfEventsRead; i++) {
+        jobject record = env->NewObject(INPUT_RECORD_Class,
+                                        INPUT_RECORD_Constructor);
+        env->SetShortField(record, INPUT_RECORD_EventType, buffer[i].EventType);
+        switch (buffer[i].EventType) {
+            case KEY_EVENT: {
+                jobject keyEvent = env->NewObject(KEY_EVENT_RECORD_Class,
+                                                  KEY_EVENT_RECORD_Constructor);
+                env->SetBooleanField(keyEvent, KEY_EVENT_RECORD_bKeyDown, buffer[i].Event.KeyEvent.bKeyDown);
+                env->SetShortField(keyEvent, KEY_EVENT_RECORD_wRepeatCount, buffer[i].Event.KeyEvent.wRepeatCount);
+                env->SetShortField(keyEvent, KEY_EVENT_RECORD_wVirtualKeyCode, buffer[i].Event.KeyEvent.wVirtualKeyCode);
+                env->SetShortField(keyEvent, KEY_EVENT_RECORD_wVirtualScanCode, buffer[i].Event.KeyEvent.wVirtualScanCode);
+
+                jobject unionChar = env->NewObject(UnionChar_Class,
+                                                   UnionChar_Constructor);
+
+                env->SetIntField(unionChar, UnionChar_UnicodeChar, buffer[i].Event.KeyEvent.uChar.UnicodeChar);
+
+                env->SetObjectField(keyEvent, KEY_EVENT_RECORD_uChar, unionChar);
+
+                env->SetIntField(keyEvent, KEY_EVENT_RECORD_dwControlKeyState, buffer[i].Event.KeyEvent.dwControlKeyState);
+
+                jobject event = env->NewObject(EventUnion_Class,
+                                               EventUnion_Constructor);
+
+                env->SetObjectField(event, EventUnion_KeyEvent, keyEvent);
+                env->SetObjectField(record, INPUT_RECORD_Event, event);
+                break;
+            }
+            case MOUSE_EVENT: {
+                jobject mouseEvent = env->NewObject(MOUSE_EVENT_RECORD_Class,
+                                                    MOUSE_EVENT_RECORD_Constructor);
+
+                jobject dwMousePosition = env->NewObject(COORD_Class,
+                                                         COORD_Constructor);
+                env->SetIntField(dwMousePosition, COORD_X, buffer[i].Event.MouseEvent.dwMousePosition.X);
+                env->SetIntField(dwMousePosition, COORD_Y, buffer[i].Event.MouseEvent.dwMousePosition.Y);
+                env->SetObjectField(mouseEvent, MOUSE_EVENT_RECORD_dwMousePosition, dwMousePosition);
+                env->SetIntField(mouseEvent, MOUSE_EVENT_RECORD_dwButtonState, buffer[i].Event.MouseEvent.dwButtonState);
+                env->SetIntField(mouseEvent, MOUSE_EVENT_RECORD_dwControlKeyState, buffer[i].Event.MouseEvent.dwControlKeyState);
+                env->SetIntField(mouseEvent, MOUSE_EVENT_RECORD_dwEventFlags, buffer[i].Event.MouseEvent.dwEventFlags);
+
+                jobject event = env->NewObject(EventUnion_Class,
+                                               EventUnion_Constructor);
+
+                env->SetObjectField(event, EventUnion_MouseEvent, mouseEvent);
+                env->SetObjectField(record, INPUT_RECORD_Event, event);
+                break;
+            }
+            case WINDOW_BUFFER_SIZE_EVENT: {
+                jobject windowBufferSize = env->NewObject(WINDOW_BUFFER_SIZE_RECORD_Class,
+                                                          WINDOW_BUFFER_SIZE_RECORD_Constructor);
+
+                jobject dwSize = env->NewObject(COORD_Class,
+                                                COORD_Constructor);
+                env->SetIntField(dwSize, COORD_X, buffer[i].Event.WindowBufferSizeEvent.dwSize.X);
+                env->SetIntField(dwSize, COORD_Y, buffer[i].Event.WindowBufferSizeEvent.dwSize.Y);
+                env->SetObjectField(windowBufferSize, WINDOW_BUFFER_SIZE_RECORD_dwSize, dwSize);
+
+                jobject event = env->NewObject(EventUnion_Class,
+                                               EventUnion_Constructor);
+
+                env->SetObjectField(event, EventUnion_WindowBufferSizeEvent, windowBufferSize);
+                env->SetObjectField(record, INPUT_RECORD_Event, event);
+                break;
+            }
+            case MENU_EVENT: {
+                jobject menuEvent = env->NewObject(MENU_EVENT_RECORD_Class,
+                                                          MENU_EVENT_RECORD_Constructor);
+
+                env->SetBooleanField(menuEvent, MENU_EVENT_RECORD_dwCommandId, buffer[i].Event.MenuEvent.dwCommandId);
+
+                jobject event = env->NewObject(EventUnion_Class,
+                                               EventUnion_Constructor);
+
+                env->SetObjectField(event, EventUnion_MenuEvent, menuEvent);
+                env->SetObjectField(record, INPUT_RECORD_Event, event);
+                break;
+            }
+            case FOCUS_EVENT: {
+                jobject focusEvent = env->NewObject(FOCUS_EVENT_RECORD_Class,
+                                                    FOCUS_EVENT_RECORD_Constructor);
+
+                env->SetIntField(focusEvent, FOCUS_EVENT_RECORD_bSetFocus, buffer[i].Event.FocusEvent.bSetFocus);
+
+                jobject event = env->NewObject(EventUnion_Class,
+                                               EventUnion_Constructor);
+
+                env->SetObjectField(event, EventUnion_FocusEvent, focusEvent);
+                env->SetObjectField(record, INPUT_RECORD_Event, event);
+                break;
+            }
+        }
+        env->SetObjectArrayElement(out_lpBuffer, i, record);
+    }
+    env->SetIntField(out_lpNumberOfEventsRead, intByReferenceValue, numberOfEventsRead);
+    delete buffer;
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    SetConsoleCursorPosition
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/COORD;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_SetConsoleCursorPosition
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jobject in_dwCursorPosition) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    COORD coord;
+    coord.X = (SHORT) env->GetLongField(in_dwCursorPosition, COORD_X);
+    coord.Y = (SHORT) env->GetLongField(in_dwCursorPosition, COORD_Y);
+    if (!SetConsoleCursorPosition(h, coord)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return;
+    }
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    SetConsoleMode
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;I)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_SetConsoleMode
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jint in_dwMode) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    if (!SetConsoleMode(h, in_dwMode)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    SetConsoleTextAttribute
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;S)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_SetConsoleTextAttribute
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jshort in_wAttributes) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    if (!SetConsoleTextAttribute(h, in_wAttributes)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    SetConsoleTitle
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_SetConsoleTitle
+  (JNIEnv *env, jobject, jstring in_lpConsoleTitle) {
+    const char *chars = env->GetStringUTFChars(in_lpConsoleTitle, NULL);
+    if (!SetConsoleTitle(chars)) {
+        env->ReleaseStringUTFChars(in_lpConsoleTitle, chars);
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+    env->ReleaseStringUTFChars(in_lpConsoleTitle, chars);
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    WriteConsoleW
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;[CILjdk/internal/org/jline/terminal/impl/jna/win/IntByReference;Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_WriteConsoleW
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jcharArray in_lpBuffer, jint in_nNumberOfCharsToWrite, jobject out_lpNumberOfCharsWritten, jobject) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+    jchar *chars = new jchar[in_nNumberOfCharsToWrite];
+    env->GetCharArrayRegion(in_lpBuffer, 0, in_nNumberOfCharsToWrite, chars);
+    DWORD written;
+    if (!WriteConsoleW(h, chars, in_nNumberOfCharsToWrite, &written, NULL)) {
+        delete chars;
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+
+    env->SetIntField(out_lpNumberOfCharsWritten, intByReferenceValue, written);
+    delete chars;
+}
+
+/*
+ * Class:     jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl
+ * Method:    ScrollConsoleScreenBuffer
+ * Signature: (Ljdk/internal/org/jline/terminal/impl/jna/win/Pointer;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/SMALL_RECT;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/SMALL_RECT;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/COORD;Ljdk/internal/org/jline/terminal/impl/jna/win/Kernel32/CHAR_INFO;)V
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_org_jline_terminal_impl_jna_win_Kernel32Impl_ScrollConsoleScreenBuffer
+  (JNIEnv *env, jobject kernel, jobject in_hConsoleOutput, jobject in_lpScrollRectangle, jobject in_lpClipRectangle, jobject in_dwDestinationOrigin, jobject in_lpFill) {
+    HANDLE h = GetStdHandle((jint) env->GetLongField(in_hConsoleOutput, pointerValue));
+
+    SMALL_RECT scrollRectangle;
+    scrollRectangle.Left = (SHORT) env->GetLongField(in_lpScrollRectangle, SMALL_RECT_Left);
+    scrollRectangle.Top = (SHORT) env->GetLongField(in_lpScrollRectangle, SMALL_RECT_Top);
+    scrollRectangle.Right = (SHORT) env->GetLongField(in_lpScrollRectangle, SMALL_RECT_Right);
+    scrollRectangle.Bottom = (SHORT) env->GetLongField(in_lpScrollRectangle, SMALL_RECT_Bottom);
+
+    SMALL_RECT clipRectangle;
+    clipRectangle.Left = (SHORT) env->GetLongField(in_lpClipRectangle, SMALL_RECT_Left);
+    clipRectangle.Top = (SHORT) env->GetLongField(in_lpClipRectangle, SMALL_RECT_Top);
+    clipRectangle.Right = (SHORT) env->GetLongField(in_lpClipRectangle, SMALL_RECT_Right);
+    clipRectangle.Bottom = (SHORT) env->GetLongField(in_lpClipRectangle, SMALL_RECT_Bottom);
+
+    COORD destinationOrigin;
+    destinationOrigin.X = (SHORT) env->GetLongField(in_dwDestinationOrigin, COORD_X);
+    destinationOrigin.Y = (SHORT) env->GetLongField(in_dwDestinationOrigin, COORD_Y);
+
+    CHAR_INFO charInfo;
+    charInfo.Char.UnicodeChar = env->GetCharField(env->GetObjectField(in_lpFill, CHAR_INFO_uChar), UnionChar_UnicodeChar);
+    charInfo.Attributes = env->GetShortField(in_lpFill, CHAR_INFO_Attributes);
+
+    if (!ScrollConsoleScreenBuffer(h, &scrollRectangle, &clipRectangle, destinationOrigin, &charInfo)) {
+        DWORD error = GetLastError();
+        jobject exc = env->NewObject(lastErrorExceptionClass,
+                                     lastErrorExceptionConstructor,
+                                     (jlong) error);
+        env->Throw((jthrowable) exc);
+        return ;
+    }
+}
--- a/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jdk_internal_jline_WindowsTerminal.h"
-
-#include <stdlib.h>
-#include <Wincon.h>
-#include <Winuser.h>
-
-static jclass recordClass;
-static jmethodID recordConstructor;
-static jclass bufferStateClass;
-static jmethodID bufferStateConstructor;
-
-JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_initIDs
-  (JNIEnv *env, jclass) {
-    jclass cls = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
-    CHECK_NULL(cls);
-    recordClass = (jclass) env->NewGlobalRef(cls);
-    CHECK_NULL(recordClass);
-    recordConstructor = env->GetMethodID(cls, "<init>", "(ZCIII)V");
-    CHECK_NULL(recordConstructor);
-    cls = env->FindClass("jdk/internal/jline/extra/AnsiInterpretingOutputStream$BufferState");
-    CHECK_NULL(cls);
-    bufferStateClass = (jclass) env->NewGlobalRef(cls);
-    CHECK_NULL(bufferStateClass);
-    bufferStateConstructor = env->GetMethodID(cls, "<init>", "(IIII)V");
-    CHECK_NULL(bufferStateConstructor);
-}
-
-JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleMode
-  (JNIEnv *, jobject) {
-    HANDLE hStdIn;
-    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return -1;
-    }
-    DWORD fdwMode;
-    if (! GetConsoleMode(hStdIn, &fdwMode)) {
-        return -1;
-    }
-    return fdwMode;
-}
-
-JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_setConsoleMode
-  (JNIEnv *, jobject, jint mode) {
-    HANDLE hStdIn;
-    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return ;
-    }
-    DWORD fdwMode = mode;
-    SetConsoleMode(hStdIn, fdwMode);
-}
-
-JNIEXPORT jobject JNICALL Java_jdk_internal_jline_WindowsTerminal_readKeyEvent
-  (JNIEnv *env, jobject) {
-    HANDLE hStdIn;
-    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return NULL;
-    }
-    INPUT_RECORD record;
-    DWORD n;
-    while (TRUE) {
-        if (ReadConsoleInputW(hStdIn, &record, 1, &n) == 0) {
-            return NULL;
-        }
-        if (record.EventType == KEY_EVENT) {
-            return env->NewObject(recordClass,
-                                  recordConstructor,
-                                  record.Event.KeyEvent.bKeyDown,
-                                  record.Event.KeyEvent.uChar.UnicodeChar,
-                                  record.Event.KeyEvent.dwControlKeyState,
-                                  record.Event.KeyEvent.wVirtualKeyCode,
-                                  record.Event.KeyEvent.wRepeatCount);
-        }
-        continue;
-    }
-}
-
-JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleOutputCodepage
-  (JNIEnv *, jobject) {
-    return GetConsoleOutputCP();
-}
-
-JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth
-  (JNIEnv *, jobject) {
-    HANDLE hStdOut;
-    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return -1;
-    }
-    CONSOLE_SCREEN_BUFFER_INFO info;
-    if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
-        return -1;
-    }
-    return info.srWindow.Right - info.srWindow.Left;
-}
-
-JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight
-  (JNIEnv *, jobject) {
-    HANDLE hStdOut;
-    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return -1;
-    }
-    CONSOLE_SCREEN_BUFFER_INFO info;
-    if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
-        return -1;
-    }
-    return info.srWindow.Bottom - info.srWindow.Top + 1;
-}
-
-JNIEXPORT jobject JNICALL Java_jdk_internal_jline_WindowsTerminal_getBufferState
-  (JNIEnv *env, jobject) {
-    HANDLE hStdOut;
-    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return NULL;
-    }
-    CONSOLE_SCREEN_BUFFER_INFO info;
-    if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
-        return NULL;
-    }
-    return env->NewObject(bufferStateClass,
-                          bufferStateConstructor,
-                          info.dwCursorPosition.X,
-                          info.dwCursorPosition.Y,
-                          info.dwSize.X,
-                          info.dwSize.Y);
-}
-
-JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_setCursorPosition
-  (JNIEnv *, jobject, jint x, jint y) {
-    HANDLE hStdOut;
-    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
-        return ;
-    }
-    COORD coord = {(SHORT) x, (SHORT) y};
-    SetConsoleCursorPosition(hStdOut, coord);
-}
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 
 package jdk.internal.jshell.tool;
 
+
 import jdk.jshell.SourceCodeAnalysis.Documentation;
 import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
@@ -32,7 +33,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -40,29 +44,39 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import jdk.internal.shellsupport.doc.JavadocFormatter;
-import jdk.internal.jline.NoInterruptUnixTerminal;
-import jdk.internal.jline.Terminal;
-import jdk.internal.jline.TerminalFactory;
-import jdk.internal.jline.TerminalSupport;
-import jdk.internal.jline.WindowsTerminal;
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.KeyMap;
-import jdk.internal.jline.console.UserInterruptException;
-import jdk.internal.jline.console.history.History;
-import jdk.internal.jline.console.history.MemoryHistory;
-import jdk.internal.jline.extra.EditingHistory;
-import jdk.internal.jline.internal.NonBlockingInputStream;
 import jdk.internal.jshell.tool.StopDetectingInputStream.State;
 import jdk.internal.misc.Signal;
 import jdk.internal.misc.Signal.Handler;
+import jdk.internal.org.jline.keymap.KeyMap;
+import jdk.internal.org.jline.reader.Binding;
+import jdk.internal.org.jline.reader.EOFError;
+import jdk.internal.org.jline.reader.History;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.LineReader.Option;
+import jdk.internal.org.jline.reader.Parser;
+import jdk.internal.org.jline.reader.UserInterruptException;
+import jdk.internal.org.jline.reader.Widget;
+import jdk.internal.org.jline.reader.impl.LineReaderImpl;
+import jdk.internal.org.jline.reader.impl.completer.ArgumentCompleter.ArgumentLine;
+import jdk.internal.org.jline.reader.impl.history.DefaultHistory;
+import jdk.internal.org.jline.terminal.impl.LineDisciplineTerminal;
+import jdk.internal.org.jline.terminal.Attributes;
+import jdk.internal.org.jline.terminal.Attributes.ControlChar;
+import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.Terminal;
+import jdk.internal.org.jline.terminal.TerminalBuilder;
+import jdk.internal.org.jline.utils.Display;
+import jdk.internal.org.jline.utils.NonBlockingReader;
 import jdk.jshell.ExpressionSnippet;
 import jdk.jshell.Snippet;
 import jdk.jshell.Snippet.SubKind;
@@ -73,73 +87,117 @@
 
     private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
 
+    final boolean allowIncompleteInputs;
     final JShellTool repl;
     final StopDetectingInputStream input;
-    final ConsoleReader in;
-    final EditingHistory history;
-    final MemoryHistory userInputHistory = new MemoryHistory();
+    final Attributes originalAttributes;
+    final LineReaderImpl in;
+    final History userInputHistory = new DefaultHistory();
+    final Instant historyLoad;
 
     String prefix = "";
 
     ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout) throws Exception {
+        this.allowIncompleteInputs = Boolean.getBoolean("jshell.test.allow.incomplete.inputs");
         this.repl = repl;
-        this.input = new StopDetectingInputStream(() -> repl.stop(), ex -> repl.hard("Error on input: %s", ex));
-        Terminal term;
+        Map<String, Object> variables = new HashMap<>();
+        this.input = new StopDetectingInputStream(() -> repl.stop(),
+                                                  ex -> repl.hard("Error on input: %s", ex));
+        Terminal terminal;
         if (System.getProperty("test.jdk") != null) {
-            term = new TestTerminal(input);
-        } else if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) {
-            term = new JShellWindowsTerminal(input);
+            terminal = new TestTerminal(input, cmdout);
+            input.setInputStream(cmdin);
         } else {
-            term = new JShellUnixTerminal(input);
+            terminal = TerminalBuilder.builder().inputStreamWrapper(in -> {
+                input.setInputStream(in);
+                return input;
+            }).build();
         }
-        term.init();
-        CompletionState completionState = new CompletionState();
-        in = new ConsoleReader(cmdin, cmdout, term) {
-            @Override public KeyMap getKeys() {
-                return new CheckCompletionKeyMap(super.getKeys(), completionState);
+        originalAttributes = terminal.getAttributes();
+        Attributes noIntr = new Attributes(originalAttributes);
+        noIntr.setControlChar(ControlChar.VINTR, 0);
+        terminal.setAttributes(noIntr);
+        terminal.enterRawMode();
+        LineReaderImpl reader = new LineReaderImpl(terminal, "jshell", variables) {
+            {
+                //jline can handle the CONT signal on its own, but (currently) requires sun.misc for it
+                try {
+                    Signal.handle(new Signal("CONT"), new Handler() {
+                        @Override public void handle(Signal sig) {
+                            try {
+                                handleSignal(jdk.internal.org.jline.terminal.Terminal.Signal.CONT);
+                            } catch (Exception ex) {
+                                ex.printStackTrace();
+                            }
+                        }
+                    });
+                } catch (IllegalArgumentException ignored) {
+                    //the CONT signal does not exist on this platform
+                }
+            }
+            CompletionState completionState = new CompletionState();
+            @Override
+            protected boolean doComplete(CompletionType lst, boolean useMenu, boolean prefix) {
+                return ConsoleIOContext.this.complete(completionState);
             }
             @Override
-            protected boolean complete() throws IOException {
-                return ConsoleIOContext.this.complete(completionState);
+            public Binding readBinding(KeyMap<Binding> keys, KeyMap<Binding> local) {
+                completionState.actionCount++;
+                return super.readBinding(keys, local);
             }
         };
-        in.setExpandEvents(false);
-        in.setHandleUserInterrupt(true);
-        List<String> persistenHistory = Stream.of(repl.prefs.keys())
-                                              .filter(key -> key.startsWith(HISTORY_LINE_PREFIX))
-                                              .sorted()
-                                              .map(key -> repl.prefs.get(key))
-                                              .collect(Collectors.toList());
-        in.setHistory(history = new EditingHistory(in, persistenHistory) {
-            @Override protected boolean isComplete(CharSequence input) {
-                return repl.analysis.analyzeCompletion(input.toString()).completeness().isComplete();
+
+        reader.setOpt(Option.DISABLE_EVENT_EXPANSION);
+
+        reader.setParser((line, cursor, context) -> {
+            if (!allowIncompleteInputs && !repl.isComplete(line)) {
+                throw new EOFError(cursor, cursor, line);
             }
+            return new ArgumentLine(line, cursor);
         });
-        in.setBellEnabled(true);
-        in.setCopyPasteDetection(true);
-        bind(FIXES_SHORTCUT, (Runnable) () -> fixes());
-        try {
-            Signal.handle(new Signal("CONT"), new Handler() {
-                @Override public void handle(Signal sig) {
-                    try {
-                        in.getTerminal().reset();
-                        in.redrawLine();
-                        in.flush();
-                    } catch (Exception ex) {
-                        ex.printStackTrace();
-                    }
-                }
-            });
-        } catch (IllegalArgumentException ignored) {
-            //the CONT signal does not exist on this platform
+
+        reader.getKeyMaps().get(LineReader.MAIN)
+              .bind((Widget) () -> fixes(), FIXES_SHORTCUT);
+        reader.getKeyMaps().get(LineReader.MAIN)
+              .bind((Widget) () -> { throw new UserInterruptException(""); }, "\003");
+
+        List<String> loadHistory = new ArrayList<>();
+        Stream.of(repl.prefs.keys())
+              .filter(key -> key.startsWith(HISTORY_LINE_PREFIX))
+              .sorted()
+              .map(key -> repl.prefs.get(key))
+              .forEach(loadHistory::add);
+
+        for (ListIterator<String> it = loadHistory.listIterator(); it.hasNext(); ) {
+            String current = it.next();
+
+            int trailingBackSlashes = countTrailintBackslashes(current);
+            boolean continuation = trailingBackSlashes % 2 != 0;
+            current = current.substring(0, current.length() - trailingBackSlashes / 2 - (continuation ? 1 : 0));
+            if (continuation && it.hasNext()) {
+                String next = it.next();
+                it.remove();
+                it.previous();
+                current += "\n" + next;
+            }
+
+            it.set(current);
         }
+
+        historyLoad = Instant.now();
+        loadHistory.forEach(line -> reader.getHistory().add(historyLoad, line));
+
+        in = reader;
     }
 
     @Override
-    public String readLine(String prompt, String prefix) throws IOException, InputInterruptedException {
+    public String readLine(String firstLinePrompt, String continuationPrompt,
+                           boolean firstLine, String prefix) throws IOException, InputInterruptedException {
+        assert firstLine || allowIncompleteInputs;
         this.prefix = prefix;
         try {
-            return in.readLine(prompt);
+            in.setVariable(LineReader.SECONDARY_PROMPT_PATTERN, continuationPrompt);
+            return in.readLine(firstLinePrompt);
         } catch (UserInterruptException ex) {
             throw (InputInterruptedException) new InputInterruptedException().initCause(ex);
         }
@@ -152,7 +210,10 @@
 
     @Override
     public Iterable<String> history(boolean currentSession) {
-        return history.entries(currentSession);
+        return StreamSupport.stream(getHistory().spliterator(), false)
+                            .filter(entry -> !currentSession || !historyLoad.equals(entry.time()))
+                            .map(entry -> entry.line())
+                            .collect(Collectors.toList());
     }
 
     @Override
@@ -163,7 +224,11 @@
                 repl.prefs.remove(key);
             }
         }
-        Collection<? extends String> savedHistory = history.save();
+        Collection<String> savedHistory =
+            StreamSupport.stream(in.getHistory().spliterator(), false)
+                         .map(History.Entry::line)
+                         .flatMap(this::toSplitEntries)
+                         .collect(Collectors.toList());
         if (!savedHistory.isEmpty()) {
             int len = (int) Math.ceil(Math.log10(savedHistory.size()+1));
             String format = HISTORY_LINE_PREFIX + "%0" + len + "d";
@@ -173,25 +238,46 @@
             }
         }
         repl.prefs.flush();
-        in.close();
         try {
-            in.getTerminal().restore();
+            in.getTerminal().setAttributes(originalAttributes);
+            in.getTerminal().close();
         } catch (Exception ex) {
             throw new IOException(ex);
         }
         input.shutdown();
     }
 
-    private void bind(String shortcut, Object action) {
-        KeyMap km = in.getKeys();
-        for (int i = 0; i < shortcut.length(); i++) {
-            Object value = km.getBound(Character.toString(shortcut.charAt(i)));
-            if (value instanceof KeyMap) {
-                km = (KeyMap) value;
+    private Stream<String> toSplitEntries(String entry) {
+        String[] lines = entry.split("\n");
+        List<String> result = new ArrayList<>();
+
+        for (int i = 0; i < lines.length; i++) {
+            StringBuilder historyLine = new StringBuilder(lines[i]);
+            int trailingBackSlashes = countTrailintBackslashes(historyLine);
+            for (int j = 0; j < trailingBackSlashes; j++) {
+                historyLine.append("\\");
+            }
+            if (i + 1 < lines.length) {
+                historyLine.append("\\");
+            }
+            result.add(historyLine.toString());
+        }
+
+        return result.stream();
+    }
+
+    private int countTrailintBackslashes(CharSequence text) {
+        int count = 0;
+
+        for (int i = text.length() - 1; i >= 0; i--) {
+            if (text.charAt(i) == '\\') {
+                count++;
             } else {
-                km.bind(shortcut.substring(i), action);
+                break;
             }
         }
+
+        return count;
     }
 
     private static final String FIXES_SHORTCUT = "\033\133\132"; //Shift-TAB
@@ -199,6 +285,7 @@
     private static final String LINE_SEPARATOR = System.getProperty("line.separator");
     private static final String LINE_SEPARATORS2 = LINE_SEPARATOR + LINE_SEPARATOR;
 
+    /*XXX:*/private static final int AUTOPRINT_THRESHOLD = 100;
     @SuppressWarnings("fallthrough")
     private boolean complete(CompletionState completionState) {
         //The completion has multiple states (invoked by subsequent presses of <tab>).
@@ -206,8 +293,8 @@
         //and placed into the todo list (completionState.todo). The todo list is
         //then followed on both the first and subsequent completion invocations:
         try {
-            String text = in.getCursorBuffer().toString();
-            int cursor = in.getCursorBuffer().cursor;
+            String text = in.getBuffer().toString();
+            int cursor = in.getBuffer().cursor();
 
             List<CompletionTask> todo = completionState.todo;
 
@@ -230,13 +317,13 @@
                                        .collect(Collectors.toList());
                 }
                 long smartCount = suggestions.stream().filter(Suggestion::matchesType).count();
-                boolean hasSmart = smartCount > 0 && smartCount <= in.getAutoprintThreshold();
+                boolean hasSmart = smartCount > 0 && smartCount <= /*in.getAutoprintThreshold()*/AUTOPRINT_THRESHOLD;
                 boolean hasBoth = hasSmart &&
                                   suggestions.stream()
                                              .map(s -> s.matchesType())
                                              .distinct()
                                              .count() == 2;
-                boolean tooManyItems = suggestions.size() > in.getAutoprintThreshold();
+                boolean tooManyItems = suggestions.size() > /*in.getAutoprintThreshold()*/AUTOPRINT_THRESHOLD;
                 CompletionTask ordinaryCompletion =
                         new OrdinaryCompletionTask(suggestions,
                                                    anchor[0],
@@ -312,8 +399,8 @@
                         //intentional fall-through
                     case NO_DATA:
                         if (!todo.isEmpty()) {
-                            in.println();
-                            in.println(todo.get(0).description());
+                            in.getTerminal().writer().println();
+                            in.getTerminal().writer().println(todo.get(0).description());
                         }
                         break OUTER;
                 }
@@ -363,9 +450,9 @@
 
                         @Override
                         public Result perform(String text, int cursor) throws IOException {
-                            in.println();
+                            in.getTerminal().writer().println();
                             for (String line : thisPageLines) {
-                                in.println(line);
+                                in.getTerminal().writer().println(line);
                             }
                             return Result.FINISH;
                         }
@@ -431,9 +518,9 @@
 
         @Override
         public Result perform(String text, int cursor) throws IOException {
-            in.println();
-            in.println(repl.getResourceString("jshell.console.no.such.command"));
-            in.println();
+            in.getTerminal().writer().println();
+            in.getTerminal().writer().println(repl.getResourceString("jshell.console.no.such.command"));
+            in.getTerminal().writer().println();
             return Result.SKIP;
         }
 
@@ -494,8 +581,8 @@
             boolean showItems = toShow.size() > 1 || showSmart;
 
             if (showItems) {
-                in.println();
-                in.printColumns(toShow);
+                in.getTerminal().writer().println();
+                printColumns(toShow);
             }
 
             if (!prefixStr.isEmpty())
@@ -518,7 +605,7 @@
 
         @Override
         public String description() {
-            if (suggestions.size() <= in.getAutoprintThreshold()) {
+            if (suggestions.size() <= /*in.getAutoprintThreshold()*/AUTOPRINT_THRESHOLD) {
                 return repl.getResourceString("jshell.console.completion.all.completions");
             } else {
                 return repl.messageFormat("jshell.console.completion.all.completions.number", suggestions.size());
@@ -540,14 +627,34 @@
             String prefixStr = prefix.map(str -> str.substring(cursor - anchor)).orElse("");
             in.putString(prefixStr);
             if (candidates.size() > 1) {
-                in.println();
-                in.printColumns(candidates);
+                in.getTerminal().writer().println();
+                printColumns(candidates);
             }
             return suggestions.isEmpty() ? Result.NO_DATA : Result.FINISH;
         }
 
     }
 
+    private void printColumns(List<? extends CharSequence> candidates) {
+        if (candidates.isEmpty()) return ;
+        int size = candidates.stream().mapToInt(CharSequence::length).max().getAsInt() + 3;
+        int columns = in.getTerminal().getWidth() / size;
+        int c = 0;
+        for (CharSequence cand : candidates) {
+            in.getTerminal().writer().print(cand);
+            for (int s = cand.length(); s < size; s++) {
+                in.getTerminal().writer().print(" ");
+            }
+            if (++c == columns) {
+                in.getTerminal().writer().println();
+                c = 0;
+            }
+        }
+        if (c != 0) {
+            in.getTerminal().writer().println();
+        }
+    }
+
     private final class CommandSynopsisTask implements CompletionTask {
 
         private final List<String> synopsis;
@@ -563,14 +670,14 @@
 
         @Override
         public Result perform(String text, int cursor) throws IOException {
-            try {
-                in.println();
-                in.println(synopsis.stream()
+//            try {
+                in.getTerminal().writer().println();
+                in.getTerminal().writer().println(synopsis.stream()
                                    .map(l -> l.replaceAll("\n", LINE_SEPARATOR))
                                    .collect(Collectors.joining(LINE_SEPARATORS2)));
-            } catch (IOException ex) {
-                throw new IllegalStateException(ex);
-            }
+//            } catch (IOException ex) {
+//                throw new IllegalStateException(ex);
+//            }
             return Result.FINISH;
         }
 
@@ -612,9 +719,9 @@
 
         @Override
         public Result perform(String text, int cursor) throws IOException {
-            in.println();
-            in.println(repl.getResourceString("jshell.console.completion.current.signatures"));
-            in.println(doc.stream().collect(Collectors.joining(LINE_SEPARATOR)));
+            in.getTerminal().writer().println();
+            in.getTerminal().writer().println(repl.getResourceString("jshell.console.completion.current.signatures"));
+            in.getTerminal().writer().println(doc.stream().collect(Collectors.joining(LINE_SEPARATOR)));
             return Result.FINISH;
         }
 
@@ -638,7 +745,7 @@
             //schedule showing javadoc:
             Terminal term = in.getTerminal();
             JavadocFormatter formatter = new JavadocFormatter(term.getWidth(),
-                                                              term.isAnsiSupported());
+                                                              true);
             Function<Documentation, String> convertor = d -> formatter.formatJavadoc(d.signature(), d.javadoc()) +
                              (d.javadoc() == null ? repl.messageFormat("jshell.console.no.javadoc")
                                                   : "");
@@ -654,23 +761,15 @@
     @Override
     public boolean terminalEditorRunning() {
         Terminal terminal = in.getTerminal();
-        if (terminal instanceof SuspendableTerminal)
-            return ((SuspendableTerminal) terminal).isRaw();
-        return false;
+        return !terminal.getAttributes().getLocalFlag(LocalFlag.ICANON);
     }
 
     @Override
     public void suspend() {
-        Terminal terminal = in.getTerminal();
-        if (terminal instanceof SuspendableTerminal)
-            ((SuspendableTerminal) terminal).suspend();
     }
 
     @Override
     public void resume() {
-        Terminal terminal = in.getTerminal();
-        if (terminal instanceof SuspendableTerminal)
-            ((SuspendableTerminal) terminal).resume();
     }
 
     @Override
@@ -688,49 +787,51 @@
 
     @Override
     public void replaceLastHistoryEntry(String source) {
-        history.fullHistoryReplace(source);
+        var it = in.getHistory().iterator();
+        while (it.hasNext()) {
+            it.next();
+        }
+        it.remove();
+        in.getHistory().add(source);
     }
 
     private static final long ESCAPE_TIMEOUT = 100;
 
-    private void fixes() {
+    private boolean fixes() {
         try {
-            int c = in.readCharacter();
+            int c = in.getTerminal().input().read();
 
             if (c == (-1)) {
-                return ;
+                return true; //TODO: true or false???
             }
 
             for (FixComputer computer : FIX_COMPUTERS) {
                 if (computer.shortcut == c) {
                     fixes(computer);
-                    return ;
+                    return true; //TODO: true of false???
                 }
             }
 
             readOutRemainingEscape(c);
 
             in.beep();
-            in.println();
-            in.println(repl.getResourceString("jshell.fix.wrong.shortcut"));
+            in.getTerminal().writer().println();
+            in.getTerminal().writer().println(repl.getResourceString("jshell.fix.wrong.shortcut"));
             in.redrawLine();
             in.flush();
         } catch (IOException ex) {
             ex.printStackTrace();
         }
+        return true;
     }
 
     private void readOutRemainingEscape(int c) throws IOException {
         if (c == '\033') {
             //escape, consume waiting input:
-            InputStream inp = in.getInput();
+            NonBlockingReader inp = in.getTerminal().reader();
 
-            if (inp instanceof NonBlockingInputStream) {
-                NonBlockingInputStream nbis = (NonBlockingInputStream) inp;
-
-                while (nbis.isNonBlockingEnabled() && nbis.peek(ESCAPE_TIMEOUT) > 0) {
-                    in.readCharacter();
-                }
+            while (inp.peek(ESCAPE_TIMEOUT) > 0) {
+                inp.read();
             }
         }
     }
@@ -738,14 +839,14 @@
     //compute possible options/Fixes based on the selected FixComputer, present them to the user,
     //and perform the selected one:
     private void fixes(FixComputer computer) {
-        String input = prefix + in.getCursorBuffer().toString();
-        int cursor = prefix.length() + in.getCursorBuffer().cursor;
+        String input = prefix + in.getBuffer().toString();
+        int cursor = prefix.length() + in.getBuffer().cursor();
         FixResult candidates = computer.compute(repl, input, cursor);
 
         try {
             final boolean printError = candidates.error != null && !candidates.error.isEmpty();
             if (printError) {
-                in.println(candidates.error);
+                in.getTerminal().writer().println(candidates.error);
             }
             if (candidates.fixes.isEmpty()) {
                 in.beep();
@@ -768,19 +869,19 @@
                     }
 
                     @Override
-                    public void perform(ConsoleReader in) throws IOException {
+                    public void perform(LineReaderImpl in) throws IOException {
                         in.redrawLine();
                     }
                 });
 
                 Map<Character, Fix> char2Fix = new HashMap<>();
-                in.println();
+                in.getTerminal().writer().println();
                 for (int i = 0; i < fixes.size(); i++) {
                     Fix fix = fixes.get(i);
                     char2Fix.put((char) ('0' + i), fix);
-                    in.println("" + i + ": " + fixes.get(i).displayName());
+                    in.getTerminal().writer().println("" + i + ": " + fixes.get(i).displayName());
                 }
-                in.print(repl.messageFormat("jshell.console.choice"));
+                in.getTerminal().writer().print(repl.messageFormat("jshell.console.choice"));
                 in.flush();
                 int read;
 
@@ -793,7 +894,7 @@
                     fix = fixes.get(0);
                 }
 
-                in.println();
+                in.getTerminal().writer().println();
 
                 fix.perform(in);
 
@@ -810,21 +911,24 @@
     @Override
     public synchronized int readUserInput() throws IOException {
         while (inputBytes == null || inputBytes.length <= inputBytesPointer) {
-            boolean prevHandleUserInterrupt = in.getHandleUserInterrupt();
             History prevHistory = in.getHistory();
+            boolean prevDisableCr = Display.DISABLE_CR;
+            Parser prevParser = in.getParser();
 
             try {
+                in.setParser((line, cursor, context) -> new ArgumentLine(line, cursor));
                 input.setState(State.WAIT);
-                in.setHandleUserInterrupt(true);
+                Display.DISABLE_CR = true;
                 in.setHistory(userInputHistory);
                 inputBytes = (in.readLine("") + System.getProperty("line.separator")).getBytes();
                 inputBytesPointer = 0;
             } catch (UserInterruptException ex) {
                 throw new InterruptedIOException();
             } finally {
+                in.setParser(prevParser);
                 in.setHistory(prevHistory);
-                in.setHandleUserInterrupt(prevHandleUserInterrupt);
                 input.setState(State.BUFFER);
+                Display.DISABLE_CR = prevDisableCr;
             }
         }
         return inputBytes[inputBytesPointer++];
@@ -841,7 +945,7 @@
         /**
          * Perform the given action.
          */
-        public void perform(ConsoleReader in) throws IOException;
+        public void perform(LineReaderImpl in) throws IOException;
     }
 
     /**
@@ -882,11 +986,11 @@
 
     private static final FixComputer[] FIX_COMPUTERS = new FixComputer[] {
         new FixComputer('v', false) { //compute "Introduce variable" Fix:
-            private void performToVar(ConsoleReader in, String type) throws IOException {
+            private void performToVar(LineReaderImpl in, String type) throws IOException {
                 in.redrawLine();
-                in.setCursorPosition(0);
+                in.getBuffer().cursor(0);
                 in.putString(type + "  = ");
-                in.setCursorPosition(in.getCursorBuffer().cursor - 3);
+                in.getBuffer().cursor(in.getBuffer().cursor() - 3);
                 in.flush();
             }
 
@@ -904,7 +1008,7 @@
                     }
 
                     @Override
-                    public void perform(ConsoleReader in) throws IOException {
+                    public void perform(LineReaderImpl in) throws IOException {
                         performToVar(in, type);
                     }
                 });
@@ -922,9 +1026,9 @@
                             }
 
                             @Override
-                            public void perform(ConsoleReader in) throws IOException {
+                            public void perform(LineReaderImpl in) throws IOException {
                                 repl.processSource("import " + type + ";");
-                                in.println("Imported: " + type);
+                                in.getTerminal().writer().println("Imported: " + type);
                                 performToVar(in, stype);
                             }
                         });
@@ -934,19 +1038,19 @@
             }
         },
         new FixComputer('m', false) { //compute "Introduce method" Fix:
-            private void performToMethod(ConsoleReader in, String type, String code) throws IOException {
+            private void performToMethod(LineReaderImpl in, String type, String code) throws IOException {
                 in.redrawLine();
                 if (!code.trim().endsWith(";")) {
                     in.putString(";");
                 }
                 in.putString(" }");
-                in.setCursorPosition(0);
+                in.getBuffer().cursor(0);
                 String afterCursor = type.equals("void")
                         ? "() { "
                         : "() { return ";
                 in.putString(type + " " + afterCursor);
                 // position the cursor where the method name should be entered (before parens)
-                in.setCursorPosition(in.getCursorBuffer().cursor - afterCursor.length());
+                in.getBuffer().cursor(in.getBuffer().cursor() - afterCursor.length());
                 in.flush();
             }
 
@@ -1009,7 +1113,7 @@
                     }
 
                     @Override
-                    public void perform(ConsoleReader in) throws IOException {
+                    public void perform(LineReaderImpl in) throws IOException {
                         performToMethod(in, type, codeToCursor);
                     }
                 });
@@ -1027,9 +1131,9 @@
                             }
 
                             @Override
-                            public void perform(ConsoleReader in) throws IOException {
+                            public void perform(LineReaderImpl in) throws IOException {
                                 repl.processSource("import " + type + ";");
-                                in.println("Imported: " + type);
+                                in.getTerminal().writer().println("Imported: " + type);
                                 performToMethod(in, stype, codeToCursor);
                             }
                         });
@@ -1051,9 +1155,9 @@
                         }
 
                         @Override
-                        public void perform(ConsoleReader in) throws IOException {
+                        public void perform(LineReaderImpl in) throws IOException {
                             repl.processSource("import " + fqn + ";");
-                            in.println("Imported: " + fqn);
+                            in.getTerminal().writer().println("Imported: " + fqn);
                             in.redrawLine();
                         }
                     });
@@ -1075,113 +1179,22 @@
         }
     };
 
-    private static final class JShellUnixTerminal extends NoInterruptUnixTerminal implements SuspendableTerminal {
-
-        private final StopDetectingInputStream input;
-
-        public JShellUnixTerminal(StopDetectingInputStream input) throws Exception {
-            this.input = input;
-        }
-
-        @Override
-        public boolean isRaw() {
-            try {
-                return getSettings().get("-a").contains("-icanon");
-            } catch (IOException | InterruptedException ex) {
-                return false;
-            }
-        }
-
-        @Override
-        public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-            return input.setInputStream(super.wrapInIfNeeded(in));
-        }
-
-        @Override
-        public void disableInterruptCharacter() {
-        }
-
-        @Override
-        public void enableInterruptCharacter() {
-        }
-
-        @Override
-        public void suspend() {
-            try {
-                getSettings().restore();
-                super.disableInterruptCharacter();
-            } catch (Exception ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-
-        @Override
-        public void resume() {
-            try {
-                init();
-            } catch (Exception ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-
+    private History getHistory() {
+        return in.getHistory();
     }
 
-    private static final class JShellWindowsTerminal extends WindowsTerminal implements SuspendableTerminal {
-
-        private final StopDetectingInputStream input;
-
-        public JShellWindowsTerminal(StopDetectingInputStream input) throws Exception {
-            this.input = input;
-        }
+    private static final class TestTerminal extends LineDisciplineTerminal {
 
-        @Override
-        public void init() throws Exception {
-            super.init();
-            setAnsiSupported(false);
-        }
-
-        @Override
-        public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-            return input.setInputStream(super.wrapInIfNeeded(in));
-        }
+        private static final int DEFAULT_HEIGHT = 24;
 
-        @Override
-        public void suspend() {
-            try {
-                restore();
-                setConsoleMode(getConsoleMode() & ~ConsoleMode.ENABLE_PROCESSED_INPUT.code);
-            } catch (Exception ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-
-        @Override
-        public void resume() {
-            try {
-                restore();
-                init();
-            } catch (Exception ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-
-        @Override
-        public boolean isRaw() {
-            return (getConsoleMode() & ConsoleMode.ENABLE_LINE_INPUT.code) == 0;
-        }
-
-    }
-
-    private static final class TestTerminal extends TerminalSupport {
-
-        private final StopDetectingInputStream input;
-        private final int height;
-
-        public TestTerminal(StopDetectingInputStream input) throws Exception {
-            super(true);
-            setAnsiSupported(true);
-            setEchoEnabled(false);
-            this.input = input;
+        public TestTerminal(StopDetectingInputStream input, OutputStream output) throws Exception {
+            super("test", "ansi", output, Charset.forName("UTF-8"));
+//            setAnsiSupported(true);
+//            setEchoEnabled(false);
+//            this.input = input;
+            Attributes a = new Attributes(getAttributes());
+            a.setLocalFlag(LocalFlag.ECHO, false);
+            setAttributes(attributes);
             int h = DEFAULT_HEIGHT;
             try {
                 String hp = System.getProperty("test.terminal.height");
@@ -1191,74 +1204,20 @@
             } catch (Throwable ex) {
                 // ignore
             }
-            this.height = h;
-        }
-
-        @Override
-        public InputStream wrapInIfNeeded(InputStream in) throws IOException {
-            return input.setInputStream(super.wrapInIfNeeded(in));
-        }
-
-        @Override
-        public int getHeight() {
-            return height;
-        }
-
-    }
+            setSize(new Size(80, h));
+            new Thread(() -> {
+                int r;
 
-    private interface SuspendableTerminal {
-        public void suspend();
-        public void resume();
-        public boolean isRaw();
-    }
-
-    private static final class CheckCompletionKeyMap extends KeyMap {
-
-        private final KeyMap del;
-        private final CompletionState completionState;
-
-        public CheckCompletionKeyMap(KeyMap del, CompletionState completionState) {
-            super(del.getName());
-            this.del = del;
-            this.completionState = completionState;
+                try {
+                    while ((r = input.read()) != (-1)) {
+                        processInputByte(r);
+                    }
+                } catch (IOException ex) {
+                    throw new IllegalStateException(ex);
+                }
+            }).start();
         }
 
-        @Override
-        public void bind(CharSequence keySeq, Object function) {
-            del.bind(keySeq, function);
-        }
-
-        @Override
-        public void bindIfNotBound(CharSequence keySeq, Object function) {
-            del.bindIfNotBound(keySeq, function);
-        }
-
-        @Override
-        public void from(KeyMap other) {
-            del.from(other);
-        }
-
-        @Override
-        public Object getAnotherKey() {
-            return del.getAnotherKey();
-        }
-
-        @Override
-        public Object getBound(CharSequence keySeq) {
-            this.completionState.actionCount++;
-
-            return del.getBound(keySeq);
-        }
-
-        @Override
-        public void setBlinkMatchingParen(boolean on) {
-            del.setBlinkMatchingParen(on);
-        }
-
-        @Override
-        public String toString() {
-            return "check: " + del.toString();
-        }
     }
 
     private static final class CompletionState {
@@ -1268,4 +1227,5 @@
         /**Precomputed completion actions. Should only be reused if actionCount == 1.*/
         public List<CompletionTask> todo = Collections.emptyList();
     }
+
 }
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
     @Override
     public abstract void close() throws IOException;
 
-    public abstract String readLine(String prompt, String prefix) throws IOException, InputInterruptedException;
+    public abstract String readLine(String firstLinePrompt, String continuationPrompt, boolean firstLine, String prefix) throws IOException, InputInterruptedException;
 
     public abstract boolean interactiveOutput();
 
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1220,45 +1220,22 @@
     private String getInput(String initial) throws IOException{
         String src = initial;
         while (live) { // loop while incomplete (and live)
-            if (!src.isEmpty()) {
-                // We have some source, see if it is complete, if so, use it
-                String check;
-
-                if (isCommand(src)) {
-                    // A command can only be incomplete if it is a /exit with
-                    // an argument
-                    int sp = src.indexOf(" ");
-                    if (sp < 0) return src;
-                    check = src.substring(sp).trim();
-                    if (check.isEmpty()) return src;
-                    String cmd = src.substring(0, sp);
-                    Command[] match = findCommand(cmd, c -> c.kind.isRealCommand);
-                    if (match.length != 1 || !match[0].command.equals("/exit")) {
-                        // A command with no snippet arg, so no multi-line input
-                        return src;
-                    }
-                } else {
-                    // For a snippet check the whole source
-                    check = src;
-                }
-                Completeness comp = analysis.analyzeCompletion(check).completeness();
-                if (comp.isComplete() || comp == Completeness.EMPTY) {
-                    return src;
-                }
+            if (!src.isEmpty() && isComplete(src)) {
+                return src;
             }
-            String prompt = interactive()
-                    ? testPrompt
-                            ? src.isEmpty()
-                                    ? "\u0005" //ENQ -- test prompt
-                                    : "\u0006" //ACK -- test continuation prompt
-                            : src.isEmpty()
-                                    ? feedback.getPrompt(currentNameSpace.tidNext())
-                                    : feedback.getContinuationPrompt(currentNameSpace.tidNext())
+            String firstLinePrompt = interactive()
+                    ? testPrompt ? " \005"
+                                 : feedback.getPrompt(currentNameSpace.tidNext())
+                    : "" // Non-interactive -- no prompt
+                    ;
+            String continuationPrompt = interactive()
+                    ? testPrompt ? " \006"
+                                 : feedback.getContinuationPrompt(currentNameSpace.tidNext())
                     : "" // Non-interactive -- no prompt
                     ;
             String line;
             try {
-                line = input.readLine(prompt, src);
+                line = input.readLine(firstLinePrompt, continuationPrompt, src.isEmpty(), src);
             } catch (InputInterruptedException ex) {
                 //input interrupted - clearing current state
                 src = "";
@@ -1279,6 +1256,33 @@
         throw new EOFException(); // not longer live
     }
 
+    public boolean isComplete(String src) {
+        String check;
+
+        if (isCommand(src)) {
+            // A command can only be incomplete if it is a /exit with
+            // an argument
+            int sp = src.indexOf(" ");
+            if (sp < 0) return true;
+            check = src.substring(sp).trim();
+            if (check.isEmpty()) return true;
+            String cmd = src.substring(0, sp);
+            Command[] match = findCommand(cmd, c -> c.kind.isRealCommand);
+            if (match.length != 1 || !match[0].command.equals("/exit")) {
+                // A command with no snippet arg, so no multi-line input
+                return true;
+            }
+        } else {
+            // For a snippet check the whole source
+            check = src;
+        }
+        Completeness comp = analysis.analyzeCompletion(check).completeness();
+        if (comp.isComplete() || comp == Completeness.EMPTY) {
+            return true;
+        }
+        return false;
+    }
+
     private boolean isCommand(String line) {
         return line.startsWith("/") && !line.startsWith("//") && !line.startsWith("/*");
     }
@@ -1853,6 +1857,9 @@
         registerCommand(new Command("intro",
                 "help.intro",
                 CommandKind.HELP_SUBJECT));
+        registerCommand(new Command("keys",
+                "help.keys",
+                CommandKind.HELP_SUBJECT));
         registerCommand(new Command("id",
                 "help.id",
                 CommandKind.HELP_SUBJECT));
@@ -4001,7 +4008,7 @@
     }
 
     @Override
-    public String readLine(String prompt, String prefix) {
+    public String readLine(String firstLinePrompt, String continuationPrompt, boolean firstLine, String prefix) {
         if (scannerIn.hasNextLine()) {
             return scannerIn.nextLine();
         } else {
@@ -4030,7 +4037,7 @@
     }
 
     @Override
-    public String readLine(String prompt, String prefix) {
+    public String readLine(String firstLinePrompt, String continuationPrompt, boolean firstLine, String prefix) {
         String s = it.hasNext()
                 ? it.next()
                 : null;
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Tue Dec 11 11:29:28 2018 +0100
@@ -571,6 +571,103 @@
 \n\
 For a list of commands: /help
 
+help.keys.summary = a description of readline-like input editing
+help.keys =\
+The jshell tool provides line editing support to allow you to navigate within\n\
+and edit snippets and commands. The current command/snippet can be edited,\n\
+or prior commands/snippets can be retrieved from history, edited, and executed.\n\
+This support is similar to readline/editline with simple emacs-like bindings.\n\
+There are also jshell tool specific key sequences.\n\
+\n\
+--- Line and history navigation ---\n\
+\n\
+Return\n\t\
+  Enters the current snippet\n\
+Left-arrow or Ctrl+B\n\t\
+  Moves backward one character\n\
+Right-arrow or Ctrl+F\n\t\
+  Moves forward one character\n\
+Up-arrow or Ctrl+P\n\t\
+  Moves up one line, backward through history\n\
+Down arrow or Ctrl+N\n\t\
+  Moves down one line, forward through history\n\
+Ctrl+A\n\t\
+  Moves to the beginning of the line\n\
+Ctrl+E\n\t\
+  Moves to the end of the line\n\
+Meta+B\n\t\
+  Moves backward one word\n\
+Meta+F\n\t\
+  Moves forward one word\n\
+Ctrl+R\n\t\
+  Search backward through history\n\
+\n\
+\n\
+--- Line and history basic editing ---\n\
+\n\
+Meta+Return or Ctrl+Return (depending on platform)\n\t\
+  Insert a new line in snippet\n\
+Ctrl+_ (underscore may require shift key) or Ctrl+X then Ctrl+U\n\t\
+  Undo edit - repeat to undo more edits\n\
+Delete\n\t\
+  Deletes the character at or after the cursor, depending on the operating system\n\
+Backspace\n\t\
+  Deletes the character before the cursor\n\
+Ctrl+K\n\t\
+  Deletes the text from the cursor to the end of the line\n\
+Meta+D\n\t\
+  Deletes the text from the cursor to the end of the word\n\
+Ctrl+W\n\t\
+  Deletes the text from the cursor to the previous white space\n\
+Ctrl+Y\n\t\
+  Pastes the most recently deleted text into the line\n\
+Meta+Y\n\t\
+  After Ctrl+Y, Meta+Y cycles through previously deleted text\n\
+Ctrl+X then Ctrl+K\n\t\
+  Delete whole snippet\n\
+\n\
+\n\
+--- Shortcuts for jshell tool ---\n\
+\n\
+For details, see: /help shortcuts\n\
+\n\
+Tab\n\t\
+  Complete Java identifier or jshell command\n\
+Shift+Tab then v\n\t\
+  Convert expression to variable declaration\n\
+Shift+Tab then m\n\t\
+  Convert statement to method declaration\n\
+Shift+Tab then i\n\t\
+  Add imports for this identifier\n\
+\n\
+\n\
+--- More line and history editing ---\n\
+\n\
+Ctrl+L\n\t\
+  Clear screen and reprint snippet\n\
+Ctrl+U\n\t\
+  Kill whole line\n\
+Ctrl+T\n\t\
+  Transpose characters\n\
+Ctrl+X then Ctrl+B\n\t\
+  Navigate to matching bracket, parenthesis, ...\n\
+Ctrl+X then =\n\t\
+  Enter show current character position mode\n\
+Ctrl+X then Ctrl+O\n\t\
+  Toggle overwrite characters vs insert characters\n\
+Meta+C\n\t\
+  Capitalize word\n\
+Meta+U\n\t\
+  Convert word to uppercase\n\
+Meta+L\n\t\
+  Convert word to lowercase\n\
+Meta+0 through Meta+9 then key\n\t\
+  Repeat the specified number of times\n\
+\n\
+Where, for example, "Ctrl+A" means hold down the control key and press A.\n\
+Where "Meta" is "Alt" on many keyboards.\n\
+Line editing support is derived from JLine 3.
+
 help.shortcuts.summary = a description of keystrokes for snippet and command completion,\n\
 information access, and automatic code generation
 help.shortcuts =\
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,67 +31,91 @@
 import java.io.PrintStream;
 import java.io.Writer;
 import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import jdk.internal.jline.NoInterruptUnixTerminal;
-import jdk.internal.jline.Terminal;
-import jdk.internal.jline.TerminalFactory;
-import jdk.internal.jline.TerminalFactory.Flavor;
-import jdk.internal.jline.WindowsTerminal;
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.KeyMap;
-import jdk.internal.jline.console.completer.CandidateListCompletionHandler;
-import jdk.internal.jline.extra.EditingHistory;
-import jdk.internal.misc.Signal;
-import jdk.internal.misc.Signal.Handler;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.CompletingParsedLine;
+import jdk.internal.org.jline.reader.EOFError;
+import jdk.internal.org.jline.reader.History;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.LineReader.Option;
+import jdk.internal.org.jline.reader.LineReaderBuilder;
+import jdk.internal.org.jline.reader.Parser;
+import jdk.internal.org.jline.reader.Parser.ParseContext;
+import jdk.internal.org.jline.reader.Widget;
+import jdk.internal.org.jline.reader.impl.LineReaderImpl;
+import jdk.internal.org.jline.reader.impl.completer.ArgumentCompleter.ArgumentLine;
+import jdk.internal.org.jline.terminal.Attributes.LocalFlag;
+import jdk.internal.org.jline.terminal.Terminal;
 
 class Console implements AutoCloseable {
     private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
-    private final ConsoleReader in;
+    private final LineReader in;
     private final File historyFile;
 
     Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
             final NashornCompleter completer, final Function<String, String> docHelper) throws IOException {
         this.historyFile = historyFile;
 
-        TerminalFactory.registerFlavor(Flavor.WINDOWS, ttyDevice -> isCygwin() ? new JJSUnixTerminal() : new JJSWindowsTerminal());
-        TerminalFactory.registerFlavor(Flavor.UNIX, ttyDevice -> new JJSUnixTerminal());
-        in = new ConsoleReader(cmdin, cmdout);
-        in.setExpandEvents(false);
-        in.setHandleUserInterrupt(true);
-        in.setBellEnabled(true);
-        in.setCopyPasteDetection(true);
-        ((CandidateListCompletionHandler) in.getCompletionHandler()).setPrintSpaceAfterFullCompletion(false);
-        final Iterable<String> existingHistory = historyFile.exists() ? Files.readAllLines(historyFile.toPath()) : null;
-        in.setHistory(new EditingHistory(in, existingHistory) {
-            @Override protected boolean isComplete(CharSequence input) {
-                return completer.isComplete(input.toString());
+        Parser parser = (line, cursor, context) -> {
+            if (context == ParseContext.COMPLETE) {
+                List<Candidate> candidates = new ArrayList<>();
+                int anchor = completer.complete(line, cursor, candidates);
+                anchor = Math.min(anchor, line.length());
+                return new CompletionLine(line.substring(anchor), cursor, candidates);
+            } else if (!completer.isComplete(line)) {
+                throw new EOFError(cursor, cursor, line);
             }
-        });
-        in.addCompleter(completer);
+            return new ArgumentLine(line, cursor);
+        };
+        in = LineReaderBuilder.builder()
+                              .option(Option.DISABLE_EVENT_EXPANSION, true)
+                              .completer((in, line, candidates) -> candidates.addAll(((CompletionLine) line).candidates))
+                              .parser(parser)
+                              .build();
+        if (historyFile.exists()) {
+            StringBuilder line = new StringBuilder();
+            for (String h : Files.readAllLines(historyFile.toPath())) {
+                if (line.length() > 0) {
+                    line.append("\n");
+                }
+                line.append(h);
+                try {
+                    parser.parse(line.toString(), line.length());
+                    in.getHistory().add(line.toString());
+                    line.delete(0, line.length());
+                } catch (EOFError e) {
+                    //continue;
+                }
+            }
+            if (line.length() > 0) {
+                in.getHistory().add(line.toString());
+            }
+        }
         Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
-        bind(DOCUMENTATION_SHORTCUT, (Runnable) ()->showDocumentation(docHelper));
-        try {
-            Signal.handle(new Signal("CONT"), new Handler() {
-                @Override public void handle(Signal sig) {
-                    try {
-                        in.getTerminal().reset();
-                        in.redrawLine();
-                        in.flush();
-                    } catch (Exception ex) {
-                        ex.printStackTrace();
-                    }
-                }
-            });
-        } catch (IllegalArgumentException ignored) {
-            //the CONT signal does not exist on this platform
-        }
+        bind(DOCUMENTATION_SHORTCUT, ()->showDocumentation(docHelper));
     }
 
-    String readLine(final String prompt) throws IOException {
+    String readLine(final String prompt, final String continuationPrompt) throws IOException {
+        in.setVariable(LineReader.SECONDARY_PROMPT_PATTERN, continuationPrompt);
         return in.readLine(prompt);
     }
 
+    String readUserLine(final String prompt) throws IOException {
+        Parser prevParser = in.getParser();
+
+        try {
+            ((LineReaderImpl) in).setParser((line, cursor, context) -> new ArgumentLine(line, cursor));
+            return in.readLine(prompt);
+        } finally {
+            ((LineReaderImpl) in).setParser(prevParser);
+        }
+    }
+
     @Override
     public void close() {
         saveHistory();
@@ -101,103 +125,62 @@
         try (Writer out = Files.newBufferedWriter(historyFile.toPath())) {
             String lineSeparator = System.getProperty("line.separator");
 
-            out.write(getHistory().save()
-                                  .stream()
-                                  .collect(Collectors.joining(lineSeparator)));
+            out.write(StreamSupport.stream(getHistory().spliterator(), false)
+                                   .map(e -> e.line())
+                                   .collect(Collectors.joining(lineSeparator)));
         } catch (final IOException exp) {}
     }
 
-    EditingHistory getHistory() {
-        return (EditingHistory) in.getHistory();
+    History getHistory() {
+        return in.getHistory();
     }
 
     boolean terminalEditorRunning() {
         Terminal terminal = in.getTerminal();
-        if (terminal instanceof JJSUnixTerminal) {
-            return ((JJSUnixTerminal) terminal).isRaw();
-        }
-        return false;
+        return !terminal.getAttributes().getLocalFlag(LocalFlag.ICANON);
     }
 
     void suspend() {
-        try {
-            in.getTerminal().restore();
-        } catch (Exception ex) {
-            throw new IllegalStateException(ex);
-        }
     }
 
     void resume() {
-        try {
-            in.getTerminal().init();
-        } catch (Exception ex) {
-            throw new IllegalStateException(ex);
-        }
+    }
+
+    private void bind(String shortcut, Widget action) {
+        in.getKeyMaps().get(LineReader.MAIN).bind(action, shortcut);
     }
 
-    static final class JJSUnixTerminal extends NoInterruptUnixTerminal {
-        JJSUnixTerminal() throws Exception {
-        }
-
-        boolean isRaw() {
-            try {
-                return getSettings().get("-a").contains("-icanon");
-            } catch (IOException | InterruptedException ex) {
-                return false;
-            }
-        }
-
-        @Override
-        public void disableInterruptCharacter() {
-        }
-
-        @Override
-        public void enableInterruptCharacter() {
+    private boolean showDocumentation(final Function<String, String> docHelper) {
+        final String buffer = in.getBuffer().toString();
+        final int cursor = in.getBuffer().cursor();
+        final String doc = docHelper.apply(buffer.substring(0, cursor));
+        if (doc != null) {
+            in.getTerminal().writer().println();
+            in.printAbove(doc);
+            return true;
+        } else {
+            return false;
         }
     }
 
-    static final class JJSWindowsTerminal extends WindowsTerminal {
-        public JJSWindowsTerminal() throws Exception {
+    private static final class CompletionLine extends ArgumentLine implements CompletingParsedLine {
+        public final List<Candidate> candidates;
+
+        public CompletionLine(String word, int cursor, List<Candidate> candidates) {
+            super(word, cursor);
+            this.candidates = candidates;
         }
 
-        @Override
-        public void init() throws Exception {
-            super.init();
-            setAnsiSupported(false);
+        public CharSequence escape(CharSequence candidate, boolean complete) {
+            return candidate;
         }
-    }
-
-    private static boolean isCygwin() {
-        return System.getenv("SHELL") != null;
-    }
 
-    private void bind(String shortcut, Object action) {
-        KeyMap km = in.getKeys();
-        for (int i = 0; i < shortcut.length(); i++) {
-            final Object value = km.getBound(Character.toString(shortcut.charAt(i)));
-            if (value instanceof KeyMap) {
-                km = (KeyMap) value;
-            } else {
-                km.bind(shortcut.substring(i), action);
-            }
+        public int rawWordCursor() {
+            return word().length();
         }
-    }
 
-    private void showDocumentation(final Function<String, String> docHelper) {
-        final String buffer = in.getCursorBuffer().buffer.toString();
-        final int cursor = in.getCursorBuffer().cursor;
-        final String doc = docHelper.apply(buffer.substring(0, cursor));
-        try {
-            if (doc != null) {
-                in.println();
-                in.println(doc);
-                in.redrawLine();
-                in.flush();
-            } else {
-                in.beep();
-            }
-        } catch (IOException ex) {
-            throw new IllegalStateException(ex);
+        public int rawWordLength() {
+            return word().length();
         }
     }
 }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,13 +30,15 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.UncheckedIOException;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
-import jdk.internal.jline.console.history.History;
+
+import jdk.internal.org.jline.reader.History;
 import jdk.nashorn.api.scripting.AbstractJSObject;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.internal.runtime.JSType;
@@ -88,11 +90,20 @@
 
             if (index >= 0 && index < (hist.size() - 1)) {
                 final CharSequence src = hist.get(index);
-                hist.replace(src);
+                var it = hist.iterator();
+                while (it.hasNext()) {
+                    it.next();
+                }
+                it.remove();
+                hist.add(src.toString());
                 err.println(src);
                 evaluator.accept(src.toString());
             } else {
-                hist.removeLast();
+                var it = hist.iterator();
+                while (it.hasNext()) {
+                    it.next();
+                }
+                it.remove();
                 err.println("no history entry @ " + (index + 1));
             }
         }
@@ -103,7 +114,13 @@
     public Object getMember(final String name) {
         switch (name) {
             case "clear":
-                return (Runnable)hist::clear;
+                return (Runnable) () -> {
+                    try {
+                    hist.purge();
+                    } catch (IOException ex) {
+                        throw new UncheckedIOException(ex);
+                    }
+                };
             case "forEach":
                 return (Function<JSObject, Object>)this::iterate;
             case "load":
@@ -132,7 +149,7 @@
     public String toString() {
         final StringBuilder buf = new StringBuilder();
         for (History.Entry e : hist) {
-            buf.append(e.value()).append('\n');
+            buf.append(e.line()).append('\n');
         }
         return buf.toString();
     }
@@ -146,7 +163,7 @@
         final File file = getFile(obj);
         try (final PrintWriter pw = new PrintWriter(file)) {
             for (History.Entry e : hist) {
-                pw.println(e.value());
+                pw.println(e.line());
             }
         } catch (final IOException exp) {
             throw new RuntimeException(exp);
@@ -167,13 +184,13 @@
 
     private void print() {
         for (History.Entry e : hist) {
-            System.out.printf("%3d %s\n", e.index() + 1, e.value());
+            System.out.printf("%3d %s\n", e.index() + 1, e.line());
         }
     }
 
     private Object iterate(final JSObject func) {
         for (History.Entry e : hist) {
-            if (JSType.toBoolean(func.call(this, e.value().toString()))) {
+            if (JSType.toBoolean(func.call(this, e.line().toString()))) {
                 break; // return true from callback to skip iteration
             }
         }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,10 +27,8 @@
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.io.OutputStream;
@@ -38,12 +36,9 @@
 import java.net.URI;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.concurrent.Callable;
 import java.util.function.Consumer;
-import java.util.function.Function;
-import jdk.internal.jline.console.completer.Completer;
-import jdk.internal.jline.console.UserInterruptException;
-import jdk.nashorn.api.scripting.NashornException;
+
+import jdk.internal.org.jline.reader.UserInterruptException;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.objects.NativeJava;
 import jdk.nashorn.internal.runtime.Context;
@@ -178,7 +173,7 @@
             // redefine readLine to use jline Console's readLine!
             ScriptingFunctions.setReadLineHelper(str-> {
                 try {
-                    return in.readLine(str);
+                    return in.readUserLine(str);
                 } catch (final IOException ioExp) {
                     throw new UncheckedIOException(ioExp);
                 }
@@ -209,9 +204,9 @@
             }
 
             while (true) {
-                String source = "";
+                String source;
                 try {
-                    source = in.readLine(prompt);
+                    source = in.readLine(prompt, prompt2);
                 } catch (final IOException ioe) {
                     err.println(ioe.toString());
                     if (env._dump_on_error) {
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/NashornCompleter.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/NashornCompleter.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,8 +31,12 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.regex.Pattern;
-import jdk.internal.jline.console.completer.Completer;
-import jdk.internal.jline.console.UserInterruptException;
+
+import jdk.internal.org.jline.reader.Candidate;
+import jdk.internal.org.jline.reader.Completer;
+import jdk.internal.org.jline.reader.LineReader;
+import jdk.internal.org.jline.reader.ParsedLine;
+import jdk.internal.org.jline.reader.UserInterruptException;
 import jdk.nashorn.api.tree.AssignmentTree;
 import jdk.nashorn.api.tree.BinaryTree;
 import jdk.nashorn.api.tree.CompilationUnitTree;
@@ -63,7 +67,7 @@
  * A simple source completer for nashorn. Handles code completion for
  * expressions as well as handles incomplete single line code.
  */
-final class NashornCompleter implements Completer {
+final class NashornCompleter {
     private final Context context;
     private final Global global;
     private final ScriptEnvironment env;
@@ -145,7 +149,7 @@
             buf.append('\n');
             String curLine = null;
             try {
-                curLine = in.readLine(prompt);
+                curLine = in.readLine(prompt, prompt);
                 buf.append(curLine);
                 line++;
             } catch (final Throwable th) {
@@ -208,8 +212,7 @@
     // Pattern to match load call
     private static final Pattern LOAD_CALL = Pattern.compile("\\s*load\\s*\\(\\s*");
 
-    @Override
-    public int complete(final String test, final int cursor, final List<CharSequence> result) {
+    public int complete(String test, int cursor, List<Candidate> candidates) {
         // check that cursor is at the end of test string. Do not complete in the middle!
         if (cursor != test.length()) {
             return cursor;
@@ -245,7 +248,7 @@
                     if (BACKSLASH_FILE_SEPARATOR) {
                         name = name.replace("\\", "\\\\");
                     }
-                    result.add("\"" + name + "\")");
+                    candidates.add(createCandidate("\"" + name + "\")"));
                     return cursor + name.length() + 3;
                 }
             }
@@ -258,9 +261,9 @@
         // Find 'right most' expression of the top level expression
         final Tree rightMostExpr = getRightMostExpression(topExpr);
         if (rightMostExpr instanceof MemberSelectTree) {
-            return completeMemberSelect(exprStr, cursor, result, (MemberSelectTree)rightMostExpr, endsWithDot);
+            return completeMemberSelect(exprStr, cursor, candidates, (MemberSelectTree)rightMostExpr, endsWithDot);
         } else if (rightMostExpr instanceof IdentifierTree) {
-            return completeIdentifier(exprStr, cursor, result, (IdentifierTree)rightMostExpr);
+            return completeIdentifier(exprStr, cursor, candidates, (IdentifierTree)rightMostExpr);
         } else {
             // expression that we cannot handle for completion
             return cursor;
@@ -284,7 +287,7 @@
     }
 
     // fill properties of the incomplete member expression
-    private int completeMemberSelect(final String exprStr, final int cursor, final List<CharSequence> result,
+    private int completeMemberSelect(final String exprStr, final int cursor, final List<Candidate> candidates,
                 final MemberSelectTree select, final boolean endsWithDot) {
         final ExpressionTree objExpr = select.getExpression();
         final String objExprCode = exprStr.substring((int)objExpr.getStartPosition(), (int)objExpr.getEndPosition());
@@ -303,12 +306,12 @@
         if (obj != null && obj != ScriptRuntime.UNDEFINED) {
             if (endsWithDot) {
                 // no user specified "prefix". List all properties of the object
-                result.addAll(propsHelper.getProperties(obj));
+                propsHelper.getProperties(obj).stream().map(this::createCandidate).forEach(candidates::add);
                 return cursor;
             } else {
                 // list of properties matching the user specified prefix
                 final String prefix = select.getIdentifier();
-                result.addAll(propsHelper.getProperties(obj, prefix));
+                propsHelper.getProperties(obj, prefix).stream().map(this::createCandidate).forEach(candidates::add);
                 return cursor - prefix.length();
             }
         }
@@ -317,10 +320,10 @@
     }
 
     // fill properties for the given (partial) identifer
-    private int completeIdentifier(final String test, final int cursor, final List<CharSequence> result,
+    private int completeIdentifier(final String test, final int cursor, final List<Candidate> candidates,
                 final IdentifierTree ident) {
         final String name = ident.getName();
-        result.addAll(propsHelper.getProperties(global, name));
+        propsHelper.getProperties(global, name).stream().map(this::createCandidate).forEach(candidates::add);
         return cursor - name.length();
     }
 
@@ -431,4 +434,8 @@
 
         return Parser.create(args.toArray(new String[0]));
     }
+
+    private Candidate createCandidate(String value) {
+        return new Candidate(value, value, null, null, null, null, false);
+    }
 }
--- a/test/jdk/jdk/internal/jline/KeyConversionTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/jdk/jdk/internal/jline/KeyConversionTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,16 @@
  * @test
  * @bug 8080679
  * @summary Verify the conversion from key events to escape sequences works properly.
- * @modules jdk.internal.le/jdk.internal.jline
- * @requires os.family == "windows"
+ * @modules jdk.internal.le/jdk.internal.org.jline.terminal
+ *          jdk.internal.le/jdk.internal.org.jline.terminal.impl
  */
 
-import jdk.internal.jline.WindowsTerminal;
-import jdk.internal.jline.WindowsTerminal.KEY_EVENT_RECORD;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+
+import jdk.internal.org.jline.terminal.Size;
+import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
 
 public class KeyConversionTest {
     public static void main(String... args) throws Exception {
@@ -38,23 +42,72 @@
     }
 
     void run() throws Exception {
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 37, 1), "\033[D"); //LEFT
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 37, 1), "\033[1;5D"); //Ctrl-LEFT
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 37, 1), "\033[1;3D"); //Alt-LEFT
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 46, 1), "\033[3~"); //delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 46, 1), "\033[3;5~"); //Ctrl-delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 46, 1), "\033[3;3~"); //Alt-delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 272, 46, 1), "\033[3;2~"); //Shift-delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 280, 46, 1), "\033[3;6~"); //Ctrl-Shift-delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 274, 46, 1), "\033[3;4~"); //Alt-Shift-delete
-        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 282, 46, 1), "\033[3;8~"); //Ctrl-Alt-Shift-delete
+        checkKeyConversion(new KeyEvent(true, (short) 37, '\0', 256), "\033OD"); //LEFT
+        checkKeyConversion(new KeyEvent(true, (short) 37, '\0', 264), "\033[1;5D"); //Ctrl-LEFT
+        checkKeyConversion(new KeyEvent(true, (short) 37, '\0', 258), "\033[1;3D"); //Alt-LEFT
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 256), "\033OP"); //F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 264), "\033[1;5P"); //Ctrl-F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 258), "\033[1;3P"); //Alt-F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 272), "\033[1;2P"); //Shift-F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 280), "\033[1;6P"); //Ctrl-Shift-F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 274), "\033[1;4P"); //Alt-Shift-F1
+        checkKeyConversion(new KeyEvent(true, (short) 112, '\0', 282), "\033[1;8P"); //Ctrl-Alt-Shift-F1
+        checkKeyConversion(new KeyEvent(true, (short) 67, '\003', 8), "\003"); //Ctrl-C
     }
 
-    void checkKeyConversion(KEY_EVENT_RECORD event, String expected) {
-        String actual = WindowsTerminal.convertKeys(event);
+    void checkKeyConversion(KeyEvent event, String expected) throws IOException {
+        StringBuilder result = new StringBuilder();
+        new AbstractWindowsTerminal(new StringWriter(), "", "windows", Charset.forName("UTF-8"),
+                                    0, true, null, in -> in) {
+            @Override
+            protected int getConsoleOutputCP() {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+            @Override
+            protected int getConsoleMode() {
+                return 0;
+            }
+            @Override
+            protected void setConsoleMode(int mode) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+            @Override
+            protected boolean processConsoleInput() throws IOException {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+            @Override
+            public Size getSize() {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+            @Override
+            public void processInputChar(char c) throws IOException {
+                result.append(c);
+            }
+            @Override
+            public void processKeyEvent(boolean isKeyDown, short virtualKeyCode,
+                                        char ch, int controlKeyState) throws IOException {
+                super.processKeyEvent(isKeyDown, virtualKeyCode, ch, controlKeyState);
+            }
+        }.processKeyEvent(event.isKeyDown, event.virtualKeyCode, event.ch, event.controlKeyState);
+        String actual = result.toString();
 
         if (!expected.equals(actual)) {
             throw new AssertionError("Expected: " + expected + "; actual: " + actual);
         }
     }
+
+    public static class KeyEvent {
+        public final boolean isKeyDown;
+        public final short virtualKeyCode;
+        public final char ch;
+        public final int controlKeyState;
+
+        public KeyEvent(boolean isKeyDown, short virtualKeyCode, char ch, int controlKeyState) {
+            this.isKeyDown = isKeyDown;
+            this.virtualKeyCode = virtualKeyCode;
+            this.ch = ch;
+            this.controlKeyState = controlKeyState;
+        }
+
+    }
 }
--- a/test/jdk/jdk/internal/jline/console/StripAnsiTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 8080679 8131913
- * @modules jdk.internal.le/jdk.internal.jline.internal
- * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
- */
-
-import jdk.internal.jline.internal.Ansi;
-
-public class StripAnsiTest {
-    public static void main(String... args) throws Exception {
-        new StripAnsiTest().run();
-    }
-
-    void run() throws Exception {
-        String withAnsi = "0\033[s1\033[2J2\033[37;4m3";
-        String expected = "0123";
-
-        String actual = Ansi.stripAnsi(withAnsi);
-
-        if (!expected.equals(actual)) {
-            throw new IllegalStateException("Did not correctly strip escape sequences: " + actual);
-        }
-    }
-}
--- a/test/jdk/jdk/internal/jline/extra/AnsiInterpretingOutputStreamTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8203827
- * @summary Verify that escape sequences intepretation (used by Windows Terminal) works properly.
- * @modules jdk.internal.le/jdk.internal.jline.extra
- * @build AnsiInterpretingOutputStreamTest
- * @run testng AnsiInterpretingOutputStreamTest
- */
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream;
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream.BufferState;
-import jdk.internal.jline.extra.AnsiInterpretingOutputStream.Performer;
-
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-@Test
-public class AnsiInterpretingOutputStreamTest {
-
-    public void testAnsiInterpretation() throws IOException {
-        BufferState[] state = new BufferState[] {new BufferState(5, 5, 10, 10)};
-        ByteArrayOutputStream result = new ByteArrayOutputStream();
-        OutputStream test = new AnsiInterpretingOutputStream("UTF-8", result, new Performer() {
-            @Override
-            public BufferState getBufferState() {
-                return state[0];
-            }
-            @Override
-            public void setCursorPosition(int cursorX, int cursorY) {
-                state[0] = new BufferState(cursorX, cursorY, state[0].sizeX, state[0].sizeY);
-                try {
-                    result.write(("<setCursorPosition(" + cursorX + ", " + cursorY + ")>").getBytes("UTF-8"));
-                } catch (IOException ex) {
-                    throw new AssertionError(ex);
-                }
-            }
-        });
-
-        Writer testWriter = new OutputStreamWriter(test, "UTF-8");
-
-        //cursor move:
-        testWriter.write("\033[A\033[3A\033[15A\n");
-        testWriter.write("\033[B\033[3B\033[15B\n");
-        testWriter.write("\033[D\033[3D\033[15D\n");
-        testWriter.write("\033[C\033[3C\033[15C\n");
-
-        //clearing line:
-        testWriter.write("\033[5D\n");
-        testWriter.write("\033[K\n");
-        testWriter.write("\033[1K\n");
-        testWriter.write("\033[2K\n");
-
-        testWriter.flush();
-
-        String expected = "<setCursorPosition(5, 4)><setCursorPosition(5, 1)><setCursorPosition(5, 0)>\n" +
-                          "<setCursorPosition(5, 1)><setCursorPosition(5, 4)><setCursorPosition(5, 9)>\n" +
-                          "<setCursorPosition(4, 9)><setCursorPosition(1, 9)><setCursorPosition(0, 9)>\n" +
-                          "<setCursorPosition(1, 9)><setCursorPosition(4, 9)><setCursorPosition(9, 9)>\n" +
-                          "<setCursorPosition(4, 9)>\n" +
-                          "     <setCursorPosition(4, 9)>\n" +
-                          "<setCursorPosition(0, 9)>    \n" +
-                          "         <setCursorPosition(0, 9)>\n";
-        String actual = new String(result.toByteArray(), "UTF-8");
-
-        assertEquals(actual, expected);
-    }
-}
--- a/test/jdk/jdk/internal/jline/extra/HistoryTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8178821 8198670
- * @summary Test Completion
- * @modules jdk.internal.le/jdk.internal.jline
- *          jdk.internal.le/jdk.internal.jline.console
- *          jdk.internal.le/jdk.internal.jline.console.history
- *          jdk.internal.le/jdk.internal.jline.extra
- * @build HistoryTest
- * @run testng HistoryTest
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import jdk.internal.jline.UnsupportedTerminal;
-import jdk.internal.jline.console.ConsoleReader;
-import jdk.internal.jline.console.history.MemoryHistory;
-import jdk.internal.jline.extra.EditingHistory;
-
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-@Test
-public class HistoryTest {
-
-    public void testHistory() throws IOException {
-        ConsoleReader in = new ConsoleReader(new ByteArrayInputStream(new byte[0]), new ByteArrayOutputStream(), new UnsupportedTerminal());
-        AtomicBoolean complete = new AtomicBoolean();
-        EditingHistory history = new EditingHistory(in, Collections.emptyList()) {
-            @Override
-            protected boolean isComplete(CharSequence input) {
-                return complete.get();
-            }
-        };
-        complete.set(false); history.add("void test() {");
-        complete.set(false); history.add("    System.err.println(1);");
-        complete.set(true);  history.add("}");
-        complete.set(true);  history.add("/exit");
-
-        previousAndAssert(history, "/exit");
-
-        history.previous(); history.previous(); history.previous();
-
-        complete.set(false); history.add("void test() { /*changed*/");
-
-        complete.set(true);
-        previousAndAssert(history, "}");
-        previousAndAssert(history, "    System.err.println(1);");
-        previousAndAssert(history, "void test() {");
-
-        assertFalse(history.previous());
-
-        nextAndAssert(history, "    System.err.println(1);");
-        nextAndAssert(history, "}");
-        nextAndAssert(history, "");
-
-        complete.set(false); history.add("    System.err.println(2);");
-        complete.set(true);  history.add("} /*changed*/");
-
-        assertEquals(history.size(), 7);
-
-        Collection<? extends String> persistentHistory = history.save();
-
-        history = new EditingHistory(in, persistentHistory) {
-            @Override
-            protected boolean isComplete(CharSequence input) {
-                return complete.get();
-            }
-        };
-
-        previousSnippetAndAssert(history, "void test() { /*changed*/");
-        previousSnippetAndAssert(history, "/exit");
-        previousSnippetAndAssert(history, "void test() {");
-
-        assertFalse(history.previousSnippet());
-
-        nextSnippetAndAssert(history, "/exit");
-        nextSnippetAndAssert(history, "void test() { /*changed*/");
-        nextSnippetAndAssert(history, "");
-
-        assertFalse(history.nextSnippet());
-
-        complete.set(false); history.add("{");
-        complete.set(true);  history.add("}");
-
-        persistentHistory = history.save();
-
-        history = new EditingHistory(in, persistentHistory) {
-            @Override
-            protected boolean isComplete(CharSequence input) {
-                return complete.get();
-            }
-        };
-
-        previousSnippetAndAssert(history, "{");
-        previousSnippetAndAssert(history, "void test() { /*changed*/");
-        previousSnippetAndAssert(history, "/exit");
-        previousSnippetAndAssert(history, "void test() {");
-
-        while (history.next());
-
-        complete.set(true);  history.add("/*current1*/");
-        complete.set(true);  history.add("/*current2*/");
-        complete.set(true);  history.add("/*current3*/");
-
-        assertEquals(history.entries(true), Arrays.asList("/*current1*/", "/*current2*/", "/*current3*/"));
-        assertEquals(history.entries(false), Arrays.asList(
-                "void test() {",
-                "    System.err.println(1);",
-                "}",
-                "/exit",
-                "void test() { /*changed*/",
-                "    System.err.println(2);",
-                "} /*changed*/",
-                "{",
-                "}",
-                "/*current1*/", "/*current2*/", "/*current3*/"), history.entries(false).toString());
-
-        history.remove(0);
-
-        assertEquals(history.entries(true), Arrays.asList("/*current1*/", "/*current2*/", "/*current3*/"));
-
-        while (history.size() > 2)
-            history.remove(0);
-
-        assertEquals(history.entries(true), Arrays.asList("/*current2*/", "/*current3*/"));
-
-        for (int i = 0; i < MemoryHistory.DEFAULT_MAX_SIZE * 2; i++) {
-            complete.set(true);  history.add("/exit");
-        }
-
-        complete.set(false); history.add("void test() { /*after full*/");
-        complete.set(false); history.add("    System.err.println(1);");
-        complete.set(true);  history.add("}");
-
-        previousSnippetAndAssert(history, "void test() { /*after full*/");
-        nextSnippetAndAssert(history, "");
-
-        assertFalse(history.nextSnippet());
-
-        while (history.previousSnippet())
-            ;
-
-        while (history.nextSnippet())
-            ;
-    }
-
-    private void previousAndAssert(EditingHistory history, String expected) {
-        assertTrue(history.previous());
-        assertEquals(history.current().toString(), expected);
-    }
-
-    private void nextAndAssert(EditingHistory history, String expected) {
-        assertTrue(history.next());
-        assertEquals(history.current().toString(), expected);
-    }
-
-    private void previousSnippetAndAssert(EditingHistory history, String expected) {
-        assertTrue(history.previousSnippet());
-        assertEquals(history.current().toString(), expected);
-    }
-
-    private void nextSnippetAndAssert(EditingHistory history, String expected) {
-        assertTrue(history.nextSnippet());
-        assertEquals(history.current().toString(), expected);
-    }
-
-}
--- a/test/langtools/jdk/jshell/CommandCompletionTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/CommandCompletionTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -170,13 +170,15 @@
                 "/edit ", "/env ", "/exit ",
                 "/help ", "/history ", "/imports ",
                 "/list ", "/methods ", "/open ", "/reload ", "/reset ",
-                "/save ", "/set ", "/types ", "/vars ", "context ", "id ", "intro ", "rerun ", "shortcuts "),
+                "/save ", "/set ", "/types ", "/vars ", "context ",
+                "id ", "intro ", "keys ", "rerun ", "shortcuts "),
                 a -> assertCompletion(a, "/? |", false,
                 "/! ", "/-<n> ", "/<id> ", "/? ", "/drop ",
                 "/edit ", "/env ", "/exit ",
                 "/help ", "/history ", "/imports ",
                 "/list ", "/methods ", "/open ", "/reload ", "/reset ",
-                "/save ", "/set ", "/types ", "/vars ", "context ", "id ", "intro ", "rerun ", "shortcuts "),
+                "/save ", "/set ", "/types ", "/vars ", "context ",
+                "id ", "intro ", "keys ", "rerun ", "shortcuts "),
                 a -> assertCompletion(a, "/help /s|", false,
                 "/save ", "/set "),
                 a -> assertCompletion(a, "/help /set |", false,
--- a/test/langtools/jdk/jshell/HistoryTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/HistoryTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,21 +25,24 @@
  * @test
  * @bug 8166744
  * @summary Test Completion
- * @modules jdk.internal.le/jdk.internal.jline.extra
+ * @modules jdk.internal.le/jdk.internal.org.jline.reader
  *          jdk.jshell/jdk.internal.jshell.tool:+open
  * @build HistoryTest
  * @run testng HistoryTest
  */
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import jdk.internal.jline.extra.EditingHistory;
+
 import org.testng.annotations.Test;
 import jdk.internal.jshell.tool.JShellTool;
 import jdk.internal.jshell.tool.JShellToolBuilder;
+import jdk.internal.org.jline.reader.History;
 import static org.testng.Assert.*;
+import org.testng.annotations.BeforeMethod;
 
 public class HistoryTest extends ReplToolTesting {
 
@@ -68,8 +71,10 @@
              a -> {
                  if (!a) {
                      try {
-                         previousAndAssert(getHistory(), "} //test");
-                         previousSnippetAndAssert(getHistory(), "void test() {");
+                         previousAndAssert(getHistory(), "void test() {\n" +
+                                                         "    System.err.println(1);\n" +
+                                                         "    System.err.println(1);\n" +
+                                                         "} //test");
                      } catch (Exception ex) {
                          throw new IllegalStateException(ex);
                      }
@@ -82,12 +87,15 @@
              a -> {
                  if (!a) {
                      try {
-                         previousAndAssert(getHistory(), "} //test2");
-                         previousSnippetAndAssert(getHistory(), "void test2() {");
-                         previousSnippetAndAssert(getHistory(), "/debug 0"); //added by test framework
-                         previousSnippetAndAssert(getHistory(), "/exit");
-                         previousSnippetAndAssert(getHistory(), "int dummy;");
-                         previousSnippetAndAssert(getHistory(), "void test() {");
+                         previousAndAssert(getHistory(), "void test2() {\n" +
+                                                         "} //test2");
+                         previousAndAssert(getHistory(), "/debug 0"); //added by test framework
+                         previousAndAssert(getHistory(), "/exit");
+                         previousAndAssert(getHistory(), "int dummy;");
+                         previousAndAssert(getHistory(), "void test() {\n" +
+                                                         "    System.err.println(1);\n" +
+                                                         "    System.err.println(1);\n" +
+                                                         "} //test");
                      } catch (Exception ex) {
                          throw new IllegalStateException(ex);
                      }
@@ -106,11 +114,14 @@
              a -> {
                  if (!a) {
                      try {
-                         previousAndAssert(getHistory(), "}");
-                         previousAndAssert(getHistory(), "}");
-                         previousAndAssert(getHistory(), "void f() {");
-                         previousAndAssert(getHistory(), "class C {");
-                         getHistory().add("class C{");
+                         previousAndAssert(getHistory(), "class C {\n" +
+                                                         "void f() {\n" +
+                                                         "}\n" +
+                                                         "}");
+                         getHistory().add("class C {\n" +
+                                          "void f() {\n" +
+                                          "}\n" +
+                                          "}");
                      } catch (Exception ex) {
                          throw new IllegalStateException(ex);
                      }
@@ -125,8 +136,14 @@
              a -> {
                  if (!a) {
                      try {
-                         previousSnippetAndAssert(getHistory(), "class C {");
-                         getHistory().add("class C{");
+                         previousAndAssert(getHistory(), "class C {\n" +
+                                                         "void f() {\n" +
+                                                         "}\n" +
+                                                         "}");
+                         getHistory().add("class C {\n" +
+                                          "void f() {\n" +
+                                          "}\n" +
+                                          "}");
                      } catch (Exception ex) {
                          throw new IllegalStateException(ex);
                      }
@@ -135,23 +152,65 @@
              });
     }
 
-    private EditingHistory getHistory() throws Exception {
+    @Test
+    public void testReadExistingHistory() {
+        prefsMap.put("HISTORY_LINE_0", "/debug 0");
+        prefsMap.put("HISTORY_LINE_1", "void test() {\\");
+        prefsMap.put("HISTORY_LINE_2", "    System.err.println(1);\\");
+        prefsMap.put("HISTORY_LINE_3", "    System.err.println(`\\\\\\\\\\");
+        prefsMap.put("HISTORY_LINE_4", "    \\\\\\");
+        prefsMap.put("HISTORY_LINE_5", "`);\\");
+        prefsMap.put("HISTORY_LINE_6", "} //test");
+        test(
+             a -> {assertCommand(a, "int i", "i ==> 0");},
+             a -> {
+                 if (!a) {
+                     try {
+                         previousAndAssert(getHistory(), "int i");
+                         previousAndAssert(getHistory(), "/debug 0"); //added by test framework
+                         previousAndAssert(getHistory(), "void test() {\n" +
+                                                         "    System.err.println(1);\n" +
+                                                         "    System.err.println(`\\\\\n" +
+                                                         "    \\\n" +
+                                                         "`);\n" +
+                                                         "} //test");
+                     } catch (Exception ex) {
+                         throw new IllegalStateException(ex);
+                     }
+                 }
+                  assertCommand(a, "/exit", "");
+             });
+        assertEquals(prefsMap.get("HISTORY_LINE_00"), "/debug 0");
+        assertEquals(prefsMap.get("HISTORY_LINE_01"), "void test() {\\");
+        assertEquals(prefsMap.get("HISTORY_LINE_02"), "    System.err.println(1);\\");
+        assertEquals(prefsMap.get("HISTORY_LINE_03"), "    System.err.println(`\\\\\\\\\\");
+        assertEquals(prefsMap.get("HISTORY_LINE_04"), "    \\\\\\");
+        assertEquals(prefsMap.get("HISTORY_LINE_05"), "`);\\");
+        assertEquals(prefsMap.get("HISTORY_LINE_06"), "} //test");
+        assertEquals(prefsMap.get("HISTORY_LINE_07"), "/debug 0");
+        assertEquals(prefsMap.get("HISTORY_LINE_08"), "int i");
+        assertEquals(prefsMap.get("HISTORY_LINE_09"), "/exit");
+        System.err.println("prefsMap: " + prefsMap);
+    }
+
+    private History getHistory() throws Exception {
         Field input = repl.getClass().getDeclaredField("input");
         input.setAccessible(true);
         Object console = input.get(repl);
-        Field history = console.getClass().getDeclaredField("history");
-        history.setAccessible(true);
-        return (EditingHistory) history.get(console);
+        Method getHistory = console.getClass().getDeclaredMethod("getHistory");
+        getHistory.setAccessible(true);
+        return (History) getHistory.invoke(console);
     }
 
-    private void previousAndAssert(EditingHistory history, String expected) {
+    private void previousAndAssert(History history, String expected) {
         assertTrue(history.previous());
         assertEquals(history.current().toString(), expected);
     }
 
-    private void previousSnippetAndAssert(EditingHistory history, String expected) {
-        assertTrue(history.previousSnippet());
-        assertEquals(history.current().toString(), expected);
+    @BeforeMethod
+    public void setUp() {
+        super.setUp();
+        System.setProperty("jshell.test.allow.incomplete.inputs", "false");
     }
 
 }
--- a/test/langtools/jdk/jshell/HistoryUITest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/HistoryUITest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,7 @@
  * @library /tools/lib
  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
  * @build Compiler UITesting
- * @build HistoryUITest
+ * @compile HistoryUITest.java
  * @run testng HistoryUITest
  */
 
@@ -42,43 +42,39 @@
 @Test
 public class HistoryUITest extends UITesting {
 
+    public HistoryUITest() {
+        super(true);
+    }
+
     public void testPrevNextSnippet() throws Exception {
         doRunTest((inputSink, out) -> {
             inputSink.write("void test1() {\nSystem.err.println(1);\n}\n");
             waitOutput(out, PROMPT);
             inputSink.write("void test2() {\nSystem.err.println(2);\n}\n");
             waitOutput(out, PROMPT);
-            inputSink.write(CTRL_UP);
-            waitOutput(out, "^void test2\\(\\) \\{");
-            inputSink.write(CTRL_UP);
-            waitOutput(out, "^" + clearOut("2() {") + "1\\(\\) \\{");
-            inputSink.write(CTRL_DOWN);
-            waitOutput(out, "^" + clearOut("1() {") + "2\\(\\) \\{");
-            inputSink.write(ENTER);
-            waitOutput(out, "^\n\u0006");
             inputSink.write(UP);
-            waitOutput(out, "^}");
+            waitOutput(out, "^void test2\\(\\) \\{\n" +
+                            CONTINUATION_PROMPT + "System.err.println\\(2\\);\n" +
+                            CONTINUATION_PROMPT + "\\}");
+            inputSink.write(UP);
+            waitOutput(out, "^\u001b\\[A");
+            inputSink.write(UP);
+            waitOutput(out, "^\u001b\\[A");
             inputSink.write(UP);
-            waitOutput(out, "^" + clearOut("}") + "System.err.println\\(2\\);");
-            inputSink.write(UP);
-            waitOutput(out, "^" + clearOut("System.err.println(2);") + "void test2\\(\\) \\{");
-            inputSink.write(UP);
-            waitOutput(out, "^" + BELL);
+            waitOutput(out, "^\u001b\\[8C1\n" +
+                            "\u001b\\[19C1\n\u001b\\[C");
             inputSink.write(DOWN);
-            waitOutput(out, "^" + clearOut("void test2() {") + "System.err.println\\(2\\);");
-            inputSink.write(DOWN);
-            waitOutput(out, "^" + clearOut("System.err.println(2);") + "}");
-            inputSink.write(DOWN);
-            waitOutput(out, "^" + clearOut("}"));
-            inputSink.write(DOWN);
-            waitOutput(out, "^" + BELL);
+            waitOutput(out, "^\u001B\\[2A\u001b\\[8C2\n" +
+                            "\u001b\\[19C2\n\u001b\\[C");
+            inputSink.write(UP);
+            waitOutput(out, "^\u001b\\[A");
+            for (int i = 0; i < 19; i++) inputSink.write("\033[C");
+            waitOutput(out, "C");
+            inputSink.write("\u0008\"Modified!\"\n");
+            waitOutput(out, PROMPT);
+            inputSink.write("test2()\n");
+            waitOutput(out, "\\u001B\\[\\?2004lModified!\n\\u001B\\[\\?2004h" + PROMPT);
         });
     }
-    //where:
-        private static final String CTRL_UP = "\033[1;5A";
-        private static final String CTRL_DOWN = "\033[1;5B";
-        private static final String UP = "\033[A";
-        private static final String DOWN = "\033[B";
-        private static final String ENTER = "\n";
 
 }
--- a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,10 @@
 @Test
 public class PasteAndMeasurementsUITest extends UITesting {
 
+    public PasteAndMeasurementsUITest() {
+        super(true);
+    }
+
     public void testPrevNextSnippet() throws Exception {
         Field cons = System.class.getDeclaredField("cons");
         cons.setAccessible(true);
@@ -55,17 +59,17 @@
         console.setAccessible(true);
         cons.set(null, console.newInstance());
         doRunTest((inputSink, out) -> {
-            inputSink.write("void test1() {\nSystem.err.println(1);\n}\n" + LOC +
-                            "void test2() {\nSystem.err.println(1);\n}\n" + LOC + LOC + LOC + LOC + LOC);
-            waitOutput(out,       "\u001b\\[6nvoid test1\\(\\) \\{\n" +
-                            "\u0006\u001b\\[6nSystem.err.println\\(1\\);\n" +
-                            "\u0006\u001b\\[6n\\}\n" +
-                            "\\|  created method test1\\(\\)\n" +
-                            PROMPT + "\u001b\\[6nvoid test2\\(\\) \\{\n" +
-                            "\u0006\u001b\\[6nSystem.err.println\\(1\\);\n" +
-                            "\u0006\u001b\\[6n\\}\n" +
-                            "\\|  created method test2\\(\\)\n" +
-                            PROMPT + "\u001b\\[6n");
+            inputSink.write("void test1() {\nSystem.err.println(1);\n}\n" + //LOC +
+                            "void test2() {\nSystem.err.println(1);\n}\n"/* + LOC + LOC + LOC + LOC + LOC*/);
+            waitOutput(out,       "void test1\\(\\)\u001B\\[2D\u001B\\[2C \\{\n" +
+                            CONTINUATION_PROMPT + "System.err.println\\(1\\)\u001B\\[3D\u001B\\[3C;\n" +
+                            CONTINUATION_PROMPT + "\\}\u001B\\[2A\u001B\\[12C\n\n\u001B\\[C\n" +
+                            "\u001B\\[\\?2004l\\|  created method test1\\(\\)\n" +
+                            "\u001B\\[\\?2004h" + PROMPT + "void test2\\(\\)\u001B\\[2D\u001B\\[2C \\{\n" +
+                            CONTINUATION_PROMPT + "System.err.println\\(1\\)\u001B\\[3D\u001B\\[3C;\n" +
+                            CONTINUATION_PROMPT + "\\}\u001B\\[2A\u001B\\[12C\n\n\u001B\\[C\n" +
+                            "\u001B\\[\\?2004l\\|  created method test2\\(\\)\n" +
+                            "\u001B\\[\\?2004h" + PROMPT);
         });
     }
         private static final String LOC = "\033[12;1R";
--- a/test/langtools/jdk/jshell/ReplToolTesting.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ReplToolTesting.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -115,7 +115,7 @@
     private Map<String, ClassInfo> classes;
     private Map<String, ImportInfo> imports;
     private boolean isDefaultStartUp = true;
-    private Map<String, String> prefsMap;
+    protected Map<String, String> prefsMap;
     private Map<String, String> envvars;
 
     public interface ReplTest {
@@ -260,6 +260,7 @@
     public void setUp() {
         prefsMap = new HashMap<>();
         envvars = new HashMap<>();
+        System.setProperty("jshell.test.allow.incomplete.inputs", "true");
     }
 
     protected void setEnvVar(String name, String value) {
@@ -491,7 +492,11 @@
             if (userinput != null) {
                 setUserInput(userinput);
             }
-            setCommandInput(cmd + "\n");
+            if (cmd.endsWith("\u0003")) {
+                setCommandInput(cmd);
+            } else {
+                setCommandInput(cmd + "\n");
+            }
         } else {
             assertOutput(getCommandOutput().trim(), out==null? out : out.trim(), "command output: " + cmd);
             assertOutput(getCommandErrorOutput(), err, "command error: " + cmd);
@@ -501,7 +506,12 @@
     }
 
     public Consumer<String> assertStartsWith(String prefix) {
-        return (output) -> assertTrue(output.trim().startsWith(prefix), "Output: \'" + output + "' does not start with: " + prefix);
+        return (output) -> {
+                            if (!output.trim().startsWith(prefix)) {
+                                int i = 0;
+        }
+            assertTrue(output.trim().startsWith(prefix), "Output: \'" + output + "' does not start with: " + prefix);
+        };
     }
 
     public void assertOutput(String got, String expected, String display) {
@@ -511,8 +521,9 @@
     }
 
     private String normalizeLineEndings(String text) {
-        return text.replace(System.getProperty("line.separator"), "\n");
+        return ANSI_CODE_PATTERN.matcher(text.replace(System.getProperty("line.separator"), "\n")).replaceAll("");
     }
+        private static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[\060-\077]*[\040-\057]*[\100-\176]");
 
     public static abstract class MemberInfo {
         public final String source;
--- a/test/langtools/jdk/jshell/StartOptionTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/StartOptionTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -44,6 +44,8 @@
 
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -90,6 +92,8 @@
         byte[] bytes = str.toByteArray();
         str.reset();
         String out = new String(bytes, StandardCharsets.UTF_8);
+        out = stripAnsi(out);
+        out = out.replaceAll("[\r\n]+", "\n");
         if (checkOut != null) {
             checkOut.accept(out);
         } else {
@@ -363,4 +367,11 @@
         usererr = null;
         cmdInStream = null;
     }
+
+    private static String stripAnsi(String str) {
+        if (str == null) return "";
+        return ANSI_CODE_PATTERN.matcher(str).replaceAll("");
+    }
+
+    public static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[\060-\077]*[\040-\057]*[\100-\176]");
 }
--- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
  *          jdk.jdeps/com.sun.tools.javap
  *          jdk.jshell/jdk.internal.jshell.tool
  * @build KullaTesting TestingInputStream ToolSimpleTest
- * @run testng ToolLocalSimpleTest
+ * @run testng/othervm ToolLocalSimpleTest
  */
 
 import java.util.Locale;
--- a/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,13 +45,15 @@
     public void testUpArrow() throws Exception {
         doRunTest((inputSink, out) -> {
             inputSink.write("int x=\n44\n");
-            waitOutput(out, "x ==> 44\n\u0005");
+            waitOutput(out, "\u001B\\[\\?2004lx ==> 44\n\u001B\\[\\?2004h" + PROMPT);
             inputSink.write("/!\n");
-            waitOutput(out, "int x=\n44;\nx ==> 44\n\u0005");
-            inputSink.write("\020");
-            waitOutput(out,   "44;");
-            inputSink.write("\020");
-            waitOutput(out,  "int x=");
+            waitOutput(out, "\u001B\\[\\?2004lint x=\n44;\nx ==> 44\n\u001B\\[\\?2004h" + PROMPT);
+            inputSink.write(UP);
+            waitOutput(out,  "int x=\n" +
+                            CONTINUATION_PROMPT + "44;");
+            inputSink.write(UP);
+            inputSink.write(UP);
+            waitOutput(out,  "\u001B\\[A\n\u001B\\[2C\u001B\\[K");
         });
     }
 
--- a/test/langtools/jdk/jshell/ToolSimpleTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ToolSimpleTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -30,7 +30,7 @@
  *          jdk.jdeps/com.sun.tools.javap
  *          jdk.jshell/jdk.internal.jshell.tool
  * @build KullaTesting TestingInputStream
- * @run testng ToolSimpleTest
+ * @run testng/othervm ToolSimpleTest
  */
 
 import java.util.ArrayList;
--- a/test/langtools/jdk/jshell/ToolTabCommandTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ToolTabCommandTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,10 @@
 @Test
 public class ToolTabCommandTest extends UITesting {
 
+    public ToolTabCommandTest() {
+        super(true);
+    }
+
     public void testCommand() throws Exception {
         // set terminal height so that help output won't hit page breaks
         System.setProperty("test.terminal.height", "1000000");
@@ -84,7 +88,7 @@
             waitOutput(out, resource("help.edit"));
 
             inputSink.write(INTERRUPT + "/env " + TAB);
-            waitOutput(out, PROMPT + "/env -\n" +
+            waitOutput(out, PROMPT + "/env \n" +
                             "-add-exports    -add-modules    -class-path     -module-path    \n" +
                             "\n" +
                             resource("jshell.console.see.synopsis") +
@@ -118,7 +122,7 @@
                             REDRAW_PROMPT + "/exit ");
             inputSink.write(INTERRUPT);
             inputSink.write("int zebraStripes = 11\n");
-            waitOutput(out, "zebraStripes ==> 11\n\u0005");
+            waitOutput(out, "\\u001B\\[\\?2004lzebraStripes ==> 11\n\\u001B\\[\\?2004h" + PROMPT);
             inputSink.write("/exit zeb" + TAB);
             waitOutput(out, "braStr.*es");
             inputSink.write(INTERRUPT + "/doesnotexist" + TAB);
--- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Tue Dec 11 11:29:28 2018 +0100
@@ -53,13 +53,17 @@
 @Test
 public class ToolTabSnippetTest extends UITesting {
 
+    public ToolTabSnippetTest() {
+        super(true);
+    }
+
     public void testExpression() throws Exception {
         Path classes = prepareZip();
         doRunTest((inputSink, out) -> {
             inputSink.write("/env -class-path " + classes.toString() + "\n");
-            waitOutput(out, resource("jshell.msg.set.restore") + "\n\u0005");
+            waitOutput(out, resource("jshell.msg.set.restore") + "\n\\u001B\\[\\?2004h" + PROMPT);
             inputSink.write("import jshelltest.*;\n");
-            waitOutput(out, "\n\u0005");
+            waitOutput(out, "\n\\u001B\\[\\?2004l\\u001B\\[\\?2004h" + PROMPT);
 
             //-> <tab>
             inputSink.write(TAB);
@@ -70,7 +74,7 @@
 
             //new JShellTes<tab>
             inputSink.write("new JShellTes" + TAB);
-            waitOutput(out, "t\nJShellTest\\(      JShellTestAux\\(   " +
+            waitOutput(out, "\nJShellTest\\(      JShellTestAux\\(   " +
                             REDRAW_PROMPT + "new JShellTest");
 
             //new JShellTest<tab>
--- a/test/langtools/jdk/jshell/UITesting.java	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/langtools/jdk/jshell/UITesting.java	Tue Dec 11 11:29:28 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,8 +44,11 @@
     protected static final String TAB = "\011";
     protected static final String INTERRUPT = "\u0003";
     protected static final String BELL = "\u0007";
-    protected static final String PROMPT = "\u0005";
-    protected static final String REDRAW_PROMPT = "\n\r" + PROMPT;
+    protected static final String PROMPT = " \u0005";
+    protected static final String CONTINUATION_PROMPT = " \u0006";
+    protected static final String REDRAW_PROMPT = "\n\r?" + PROMPT;
+    protected static final String UP = "\033[A";
+    protected static final String DOWN = "\033[B";
     private final boolean laxLineEndings;
 
     public UITesting() {
@@ -141,11 +144,11 @@
     // Return true if expected is found, false if secondary is found,
     // otherwise, time out with an IllegalStateException
     protected boolean waitOutput(StringBuilder out, String expected, String secondary) {
-        expected = expected.replaceAll("\n", laxLineEndings ? "\r?\n" : System.getProperty("line.separator"));
+        expected = expected.replaceAll("\n", laxLineEndings ? "\r*\n" : System.getProperty("line.separator"));
         Pattern expectedPattern = Pattern.compile(expected, Pattern.DOTALL);
         Pattern secondaryPattern = null;
         if (secondary != null) {
-            secondary = secondary.replaceAll("\n", laxLineEndings ? "\r?\n" : System.getProperty("line.separator"));
+            secondary = secondary.replaceAll("\n", laxLineEndings ? "\r*\n" : System.getProperty("line.separator"));
             secondaryPattern = Pattern.compile(secondary, Pattern.DOTALL);
         }
         synchronized (out) {
@@ -222,7 +225,12 @@
     }
 
     protected String resource(String key) {
-        return Pattern.quote(getResource(key));
+        return patternQuote(getResource(key));
+    }
+
+    protected String patternQuote(String str) {
+        //from JDK-6507804:
+        return str.replaceAll("([\\\\\\[\\].^$?*+{}()|])", "\\\\$1");
     }
 
     protected String getMessage(String key, Object... args) {
--- a/test/nashorn/script/nosecurity/JDK-8055034.js.EXPECTED	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/nashorn/script/nosecurity/JDK-8055034.js.EXPECTED	Tue Dec 11 11:29:28 2018 +0100
@@ -1,6 +1,3 @@
-jjs> var x = Object.create(null);
-jjs> x;
-jjs> print('PASSED');
-PASSED
+jjs> var x = Object.create(null)jjs> jjs> print('PASSED')PASSED
 jjs> exit(0)
 exit code = 0
--- a/test/nashorn/script/nosecurity/JDK-8130127.js.EXPECTED	Tue Dec 11 10:15:28 2018 +0100
+++ b/test/nashorn/script/nosecurity/JDK-8130127.js.EXPECTED	Tue Dec 11 11:29:28 2018 +0100
@@ -2,6 +2,5 @@
 
 
 
-jjs> print('hello')
-hello
+jjs> print('hello')hello
 jjs>