changeset 50338:1d5694c1aa03

8203827: Upgrade JLine to 2.14.6 Reviewed-by: alanb, hannesw, rfield
author jlahoda
date Fri, 01 Jun 2018 13:04:30 +0200
parents 4d1393781fef
children ede65c4fb6da
files 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/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/legal/jline.md src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java test/jdk/jdk/internal/jline/console/StripAnsiTest.java test/jdk/jdk/internal/jline/extra/AnsiInterpretingOutputStreamTest.java test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java test/langtools/jdk/jshell/ToolTabSnippetTest.java test/langtools/jdk/jshell/UITesting.java
diffstat 63 files changed, 3028 insertions(+), 831 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/DefaultTerminal2.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,135 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -18,6 +18,8 @@
 public class NoInterruptUnixTerminal
     extends UnixTerminal
 {
+    private String intr;
+
     public NoInterruptUnixTerminal() throws Exception {
         super();
     }
@@ -25,12 +27,20 @@
     @Override
     public void init() throws Exception {
         super.init();
-        getSettings().set("intr undef");
+        intr = getSettings().getPropertyAsString("intr");
+        if ("<undef>".equals(intr)) {
+            intr = null;
+        }
+        if (intr != null) {
+            getSettings().undef("intr");
+        }
     }
 
     @Override
     public void restore() throws Exception {
-        getSettings().set("intr ^C");
+        if (intr != null) {
+            getSettings().set("intr", intr);
+        }
         super.restore();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/OSvTerminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -60,6 +60,9 @@
 
     void setEchoEnabled(boolean enabled);
 
+    void disableInterruptCharacter();
+    void enableInterruptCharacter();
+
     String getOutputEncoding();
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal2.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -11,11 +11,9 @@
 import java.text.MessageFormat;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.Callable;
 
 import jdk.internal.jline.internal.Configuration;
 import jdk.internal.jline.internal.Log;
-import jdk.internal.jline.internal.Preconditions;
 import static jdk.internal.jline.internal.Preconditions.checkNotNull;
 
 /**
@@ -32,10 +30,14 @@
 
     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";
@@ -45,16 +47,17 @@
     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 type = Configuration.getString(JLINE_TERMINAL, AUTO);
-        if ("dumb".equals(System.getenv("TERM"))) {
-            type = "none";
-            Log.debug("$TERM=dumb; setting type=", type);
-        }
+        String defaultType = "dumb".equals(System.getenv("TERM")) ? NONE : AUTO;
+        String type  = Configuration.getString(JLINE_TERMINAL, defaultType);
 
         Log.debug("Creating terminal; type=", type);
 
@@ -65,11 +68,20 @@
             if (tmp.equals(UNIX)) {
                 t = getFlavor(Flavor.UNIX);
             }
-            else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
+            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)) {
-                t = new UnsupportedTerminal();
+                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)) {
@@ -77,8 +89,10 @@
                     Flavor flavor = Flavor.UNIX;
                     if (os.contains(WINDOWS)) {
                         flavor = Flavor.WINDOWS;
+                    } else if (System.getenv("OSV_CPUS") != null) {
+                        flavor = Flavor.OSV;
                     }
-                    t = getFlavor(flavor);
+                    t = getFlavor(flavor, ttyDevice);
                 }
                 else {
                     try {
@@ -125,6 +139,7 @@
         AUTO,
         WINDOWS,
         UNIX,
+        OSV,
         NONE
     }
 
@@ -145,31 +160,52 @@
     public static enum Flavor
     {
         WINDOWS,
-        UNIX
+        UNIX,
+        OSV
     }
 
-    private static final Map<Flavor, Callable<? extends Terminal>> FLAVORS = new HashMap<>();
+    private static final Map<Flavor, TerminalConstructor> FLAVORS = new HashMap<>();
 
     static {
-//        registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
-//        registerFlavor(Flavor.UNIX, UnixTerminal.class);
-        registerFlavor(Flavor.WINDOWS, WindowsTerminal :: new);
-        registerFlavor(Flavor.UNIX, UnixTerminal :: new);
+        registerFlavor(Flavor.WINDOWS, ttyDevice -> new WindowsTerminal());
+        registerFlavor(Flavor.UNIX, ttyDevice -> new UnixTerminal(ttyDevice));
+        registerFlavor(Flavor.OSV, ttyDevice -> new OSvTerminal());
     }
 
-    public static synchronized Terminal get() {
+    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();
+            term = create(ttyDevice);
         }
         return term;
     }
 
-    public static Terminal getFlavor(final Flavor flavor) throws Exception {
-        return FLAVORS.getOrDefault(flavor, () -> {throw new InternalError();}).call();
+    public static synchronized Terminal get() {
+        return get(null);
     }
 
-    public static void registerFlavor(final Flavor flavor, final Callable<? extends Terminal> sup) {
-        FLAVORS.put(flavor, sup);
+    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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -112,6 +112,12 @@
         Log.debug("Echo enabled: ", enabled);
     }
 
+    public void disableInterruptCharacter() {
+    }
+
+    public void enableInterruptCharacter() {
+    }
+
     public InputStream wrapInIfNeeded(InputStream in) throws IOException {
         return in;
     }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -8,9 +8,18 @@
  */
 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
@@ -27,14 +36,36 @@
  */
 public class UnixTerminal
     extends TerminalSupport
+    implements Terminal2
 {
-    private final TerminalLineSettings settings = new TerminalLineSettings();
+    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 {
-        super(true);
+        this(TerminalLineSettings.DEFAULT_TTY, null);
     }
 
-    protected TerminalLineSettings getSettings() {
+    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;
     }
 
@@ -51,10 +82,20 @@
         // 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)
-        settings.set("-icanon min 1 -icrnl -inlcr -ixon");
-        settings.set("dsusp undef");
+        //
+        // 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();
     }
 
     /**
@@ -87,6 +128,12 @@
     }
 
     @Override
+    public boolean hasWeirdWrap() {
+        return getBooleanCapability("auto_right_margin")
+                && getBooleanCapability("eat_newline_glitch");
+    }
+
+    @Override
     public synchronized void setEchoEnabled(final boolean enabled) {
         try {
             if (enabled) {
@@ -101,14 +148,18 @@
             if (e instanceof InterruptedException) {
                 Thread.currentThread().interrupt();
             }
-            Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo", e);
+            Log.error("Failed to ", enabled ? "enable" : "disable", " echo", e);
         }
     }
 
     public void disableInterruptCharacter()
     {
         try {
-            settings.set("intr undef");
+            intr = getSettings().getPropertyAsString("intr");
+            if ("<undef>".equals(intr)) {
+                intr = null;
+            }
+            settings.undef("intr");
         }
         catch (Exception e) {
             if (e instanceof InterruptedException) {
@@ -121,7 +172,9 @@
     public void enableInterruptCharacter()
     {
         try {
-            settings.set("intr ^C");
+            if (intr != null) {
+                settings.set("intr", intr);
+            }
         }
         catch (Exception e) {
             if (e instanceof InterruptedException) {
@@ -130,4 +183,62 @@
             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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -19,8 +19,12 @@
     extends TerminalSupport
 {
     public UnsupportedTerminal() {
+        this(false, true);
+    }
+
+    public UnsupportedTerminal(boolean ansiSupported, boolean echoEnabled) {
         super(false);
-        setAnsiSupported(false);
-        setEchoEnabled(true);
+        setAnsiSupported(ansiSupported);
+        setEchoEnabled(echoEnabled);
     }
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -12,7 +12,11 @@
 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;
@@ -71,7 +75,7 @@
         super.init();
 
 //        setAnsiSupported(Configuration.getBoolean(ANSI, true));
-        setAnsiSupported(false);
+        setAnsiSupported(true);
 
         //
         // FIXME: Need a way to disable direct console and sysin detection muck
@@ -115,19 +119,27 @@
             setConsoleMode(getConsoleMode() |
                 ENABLE_ECHO_INPUT.code |
                 ENABLE_LINE_INPUT.code |
-                ENABLE_PROCESSED_INPUT.code |
                 ENABLE_WINDOW_INPUT.code);
         }
         else {
             setConsoleMode(getConsoleMode() &
                 ~(ENABLE_LINE_INPUT.code |
                     ENABLE_ECHO_INPUT.code |
-                    ENABLE_PROCESSED_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.
      */
@@ -182,6 +194,22 @@
     }
 
     @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
@@ -511,6 +539,10 @@
 
     private native int getWindowsTerminalHeight();
 
+    private native BufferState getBufferState();
+
+    private native void setCursorPosition(int x, int y);
+
     /**
      * Console mode
      * <p/>
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -32,11 +32,14 @@
 
     public ConsoleKeys(String appName, URL inputrcUrl) {
         keyMaps = KeyMap.keyMaps();
+        setVar("editing-mode", "emacs");
         loadKeys(appName, inputrcUrl);
-    }
-
-    protected boolean isViEditMode() {
-        return keys.isViKeyMap();
+        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) {
@@ -60,10 +63,6 @@
         this.keys = keys;
     }
 
-    protected boolean getViEditMode() {
-        return keys.isViKeyMap ();
-    }
-
     protected void loadKeys(String appName, URL inputrcUrl) {
         keys = keyMaps.get(KeyMap.EMACS);
 
@@ -127,13 +126,8 @@
                         if (args.startsWith("term=")) {
                             // TODO
                         } else if (args.startsWith("mode=")) {
-                            if (args.equalsIgnoreCase("mode=vi")) {
-                                parsing = isViEditMode();
-                            } else if (args.equals("mode=emacs")) {
-                                parsing = !isViEditMode();
-                            } else {
-                                parsing = false;
-                            }
+                            String mode = variables.get("editing-mode");
+                            parsing = args.substring("mode=".length()).equalsIgnoreCase(mode);
                         } else {
                             parsing = args.equalsIgnoreCase(appName);
                         }
@@ -185,7 +179,7 @@
                         && 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) == '=');
+                equivalency = i + 1 < line.length() && line.charAt(i) == ':' && line.charAt(i + 1) == '=';
                 i++;
                 if (equivalency) {
                     i++;
@@ -256,7 +250,7 @@
         }
     }
 
-    private String translateQuoted(String keySeq) {
+    private static String translateQuoted(String keySeq) {
         int i;
         String str = keySeq.substring( 1, keySeq.length() - 1 );
         keySeq = "";
@@ -342,7 +336,7 @@
         return keySeq;
     }
 
-    private char getKeyFromName(String name) {
+    private static char getKeyFromName(String name) {
         if ("DEL".equalsIgnoreCase(name) || "Rubout".equalsIgnoreCase(name)) {
             return 0x7f;
         } else if ("ESC".equalsIgnoreCase(name) || "Escape".equalsIgnoreCase(name)) {
@@ -365,12 +359,6 @@
             if (keyMaps.containsKey(val)) {
                 keys = keyMaps.get(val);
             }
-        } else if ("editing-mode".equals(key)) {
-            if ("vi".equalsIgnoreCase(val)) {
-                keys = keyMaps.get(KeyMap.VI_INSERT);
-            } else if ("emacs".equalsIgnoreCase(key)) {
-                keys = keyMaps.get(KeyMap.EMACS);
-            }
         } else if ("blink-matching-paren".equals(key)) {
             if ("on".equalsIgnoreCase(val)) {
               keys.setBlinkMatchingParen(true);
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -14,9 +14,8 @@
 //import java.awt.datatransfer.Transferable;
 //import java.awt.datatransfer.UnsupportedFlavorException;
 //import java.awt.event.ActionListener;
-//import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-//import java.io.ByteArrayOutputStream;
+import java.io.BufferedReader;
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -26,24 +25,27 @@
 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.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-//import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
-//import java.util.Map;
 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;
@@ -51,13 +53,15 @@
 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 org.fusesource.jansi.AnsiOutputStream;
 
 import static jdk.internal.jline.internal.Preconditions.checkNotNull;
 
@@ -72,7 +76,7 @@
  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
  */
-public class ConsoleReader
+public class ConsoleReader implements Closeable
 {
     public static final String JLINE_NOBELL = "jline.nobell";
 
@@ -84,6 +88,8 @@
 
     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';
@@ -92,30 +98,38 @@
 
     public static final char NULL_MASK = 0;
 
-    public static final int TAB_WIDTH = 4;
+    public static final int TAB_WIDTH = 8;
 
     private static final ResourceBundle
         resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
 
-    private final Terminal terminal;
+    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 = true;
+    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 = "";
@@ -124,6 +138,10 @@
 
     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
@@ -133,12 +151,6 @@
     private long                   escapeTimeout;
     private Reader                 reader;
 
-    /*
-     * TODO: Please read the comments about this in setInput(), but this needs
-     * to be done away with.
-     */
-    private boolean                isUnitTestInput;
-
     /**
      * Last character searched for with a vi character search
      */
@@ -155,6 +167,8 @@
 
     private String encoding;
 
+    private boolean quotedInsert;
+
     private boolean recording;
 
     private String macro = "";
@@ -231,7 +245,8 @@
     {
         this.appName = appName != null ? appName : "JLine";
         this.encoding = encoding != null ? encoding : Configuration.getEncoding();
-        this.terminal = term != null ? term : TerminalFactory.get();
+        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 );
@@ -239,9 +254,49 @@
         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 URL getInputRc() throws IOException {
+    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);
@@ -260,19 +315,6 @@
 
     void setInput(final InputStream in) throws IOException {
         this.escapeTimeout = Configuration.getLong(JLINE_ESC_TIMEOUT, 100);
-        /*
-         * This is gross and here is how to fix it. In getCurrentPosition()
-         * and getCurrentAnsiRow(), the logic is disabled when running unit
-         * tests and the fact that it is a unit test is determined by knowing
-         * if the original input stream was a ByteArrayInputStream. So, this
-         * is our test to do this.  What SHOULD happen is that the unit
-         * tests should pass in a terminal that is appropriately configured
-         * such that whatever behavior they expect to happen (or not happen)
-         * happens (or doesn't).
-         *
-         * So, TODO, get rid of this and fix the unit tests.
-         */
-        this.isUnitTestInput = in instanceof ByteArrayInputStream;
         boolean nonBlockingEnabled =
                escapeTimeout > 0L
             && terminal.isSupported()
@@ -297,20 +339,30 @@
      * have completed using the reader as it shuts down and cleans up resources
      * that would otherwise be "leaked".
      */
-    public void shutdown() {
+    @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 {
-            shutdown();
+            close();
         }
         finally {
             super.finalize();
@@ -403,6 +455,24 @@
     }
 
     /**
+     * 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.
@@ -431,7 +501,7 @@
 
     public void setPrompt(final String prompt) {
         this.prompt = prompt;
-        this.promptLen = ((prompt == null) ? 0 : stripAnsi(lastLine(prompt)).length());
+        this.promptLen = (prompt == null) ? 0 : wcwidth(Ansi.stripAnsi(lastLine(prompt)), 0);
     }
 
     public String getPrompt() {
@@ -440,24 +510,11 @@
 
     /**
      * Set the echo character. For example, to have "*" entered when a password is typed:
-     * <p/>
      * <pre>
      * myConsoleReader.setEchoCharacter(new Character('*'));
      * </pre>
-     * <p/>
-     * Setting the character to
-     * <p/>
-     * <pre>
-     * null
-     * </pre>
-     * <p/>
-     * will restore normal character echoing. Setting the character to
-     * <p/>
-     * <pre>
-     * new Character(0)
-     * </pre>
-     * <p/>
-     * will cause nothing to be echoed.
+     * 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.
      */
@@ -500,9 +557,52 @@
         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() {
-        // FIXME: does not handle anything but a line with a prompt absolute position
-        return promptLen + buf.cursor;
+        return promptLen + wcwidth(buf.buffer, 0, buf.cursor, promptLen);
     }
 
     /**
@@ -510,7 +610,7 @@
      * prompt is returned if no '\n' characters are present.
      * null is returned if prompt is null.
      */
-    private String lastLine(String str) {
+    private static String lastLine(String str) {
         if (str == null) return "";
         int last = str.lastIndexOf("\n");
 
@@ -521,26 +621,10 @@
         return str;
     }
 
-    String stripAnsi(String str) {
-        if (str == null) return "";
-        return ANSI_CODE_PATTERN.matcher(str).replaceAll("");
-//        try {
-//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-//            AnsiOutputStream aos = new AnsiOutputStream(baos);
-//            aos.write(str.getBytes());
-//            aos.flush();
-//            return baos.toString();
-//        } catch (IOException e) {
-//            return str;
-//        }
-    }
-    //where:
-        private static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[^@-~]*[@-~]");
-
     /**
      * Move the cursor position to the specified absolute index.
      */
-    public final boolean setCursorPosition(final int position) throws IOException {
+    public boolean setCursorPosition(final int position) throws IOException {
         if (position == buf.cursor) {
             return true;
         }
@@ -602,17 +686,14 @@
     /**
      * Output put the prompt + the current buffer
      */
-    public final void drawLine() throws IOException {
+    public void drawLine() throws IOException {
         String prompt = getPrompt();
         if (prompt != null) {
-            print(prompt);
+            rawPrint(prompt);
         }
 
-        print(buf.buffer.toString());
-
-        if (buf.length() != buf.cursor) { // not at end of line
-            back(buf.length() - buf.cursor - 1);
-        }
+        fmtPrint(buf.buffer, 0, buf.cursor, promptLen);
+
         // force drawBuffer to check for weird wrap (after clear screen)
         drawBuffer();
     }
@@ -620,9 +701,8 @@
     /**
      * Clear the line and redraw it.
      */
-    public final void redrawLine() throws IOException {
-        print(RESET_LINE);
-//        flush();
+    public void redrawLine() throws IOException {
+        tputs("carriage_return");
         drawLine();
     }
 
@@ -824,7 +904,7 @@
         }
         String result = sb.toString();
         if (!str.equals(result)) {
-            print(result);
+            fmtPrint(result, getCursorPosition());
             println();
             flush();
         }
@@ -835,15 +915,16 @@
     /**
      * Write out the specified string to the buffer and the output stream.
      */
-    public final void putString(final CharSequence str) throws IOException {
+    public void putString(final CharSequence str) throws IOException {
+        int pos = getCursorPosition();
         buf.write(str);
         if (mask == null) {
             // no masking
-            print(str);
+            fmtPrint(str, pos);
         } else if (mask == NULL_MASK) {
             // don't print anything
         } else {
-            print(mask, str.length());
+            rawPrint(mask, str.length());
         }
         drawBuffer();
     }
@@ -856,48 +937,34 @@
      */
     private void drawBuffer(final int clear) throws IOException {
         // debug ("drawBuffer: " + clear);
-        if (buf.cursor == buf.length() && clear == 0) {
-        } else {
-            char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
+        int nbChars = buf.length() - buf.cursor;
+        if (buf.cursor != buf.length() || clear != 0) {
             if (mask != null) {
-                Arrays.fill(chars, mask);
-            }
-            if (terminal.hasWeirdWrap()) {
-                // need to determine if wrapping will occur:
-                int width = terminal.getWidth();
-                int pos = getCursorPosition();
-                for (int i = 0; i < chars.length; i++) {
-                    print(chars[i]);
-                    if ((pos + i + 1) % width == 0) {
-                        print(32); // move cursor to next line by printing dummy space
-                        print(13); // CR / not newline.
-                    }
+                if (mask != NULL_MASK) {
+                    rawPrint(mask, nbChars);
+                } else {
+                    nbChars = 0;
                 }
             } else {
-                print(chars);
-            }
-            clearAhead(clear, chars.length);
-            if (terminal.isAnsiSupported()) {
-                if (chars.length > 0) {
-                    back(chars.length);
-                }
-            } else {
-                back(chars.length);
+                fmtPrint(buf.buffer, buf.cursor, buf.length());
             }
         }
-        if (terminal.hasWeirdWrap()) {
+        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 (getCursorPosition() > 0 && (getCursorPosition() % width == 0)
-                    && buf.cursor == buf.length() && clear == 0) {
+            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
-                print(32); // move cursor to next line by printing dummy space
-                print(13); // CR / not newline.
+                rawPrint(' '); // move cursor to next line by printing dummy space
+                tputs("carriage_return"); // CR / not newline.
             }
+            cursorOk = true;
         }
+        clearAhead(clear, cursorPos);
+        back(nbChars);
     }
 
     /**
@@ -912,70 +979,69 @@
      * Clear ahead the specified number of characters without moving the cursor.
      *
      * @param num the number of characters to clear
-     * @param delta the difference between the internal cursor and the screen
-     * cursor - if > 0, assume some stuff was printed and weird wrap has to be
-     * checked
+     * @param pos the current screen cursor position
      */
-    private void clearAhead(final int num, int delta) throws IOException {
-        if (num == 0) {
-            return;
+    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);
         }
-
-        if (terminal.isAnsiSupported()) {
-            int width = terminal.getWidth();
-            int screenCursorCol = getCursorPosition() + delta;
-            // clear current line
-            printAnsiSequence("K");
-            // if cursor+num wraps, then we need to clear the line(s) below too
-            int curCol = screenCursorCol % width;
-            int endCol = (screenCursorCol + num - 1) % width;
-            int lines = num / width;
-            if (endCol < curCol) lines++;
-            for (int i = 0; i < lines; i++) {
-                printAnsiSequence("B");
-                printAnsiSequence("2K");
+        // 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;
             }
-            for (int i = 0; i < lines; i++) {
-                printAnsiSequence("A");
-            }
-            return;
+            moveCursorFromTo(cur, pos);
         }
-
-        // print blank extra characters
-        print(' ', num);
-
-        // we need to flush here so a "clever" console doesn't just ignore the redundancy
-        // of a space followed by a backspace.
-//        flush();
-
-        // reset the visual cursor
-        back(num);
-
-//        flush();
+        // Simple erasure
+        else {
+            rawPrint(' ', num);
+            moveCursorFromTo(pos + num, pos);
+        }
     }
 
     /**
-     * Move the visual cursor backwards without modifying the buffer cursor.
+     * Move the visual cursor backward without modifying the buffer cursor.
      */
     protected void back(final int num) throws IOException {
         if (num == 0) return;
-        if (terminal.isAnsiSupported()) {
-            int width = getTerminal().getWidth();
-            int cursor = getCursorPosition();
-            int realCursor = cursor + num;
-            int realCol  = realCursor % width;
-            int newCol = cursor % width;
-            int moveup = num / width;
-            int delta = realCol - newCol;
-            if (delta < 0) moveup++;
-            if (moveup > 0) {
-                printAnsiSequence(moveup + "A");
-            }
-            printAnsiSequence((1 + newCol) + "G");
-            return;
-        }
-        print(BACKSPACE, num);
-//        flush();
+        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);
     }
 
     /**
@@ -1000,37 +1066,11 @@
             return 0;
         }
 
-        int count = 0;
-
-        int termwidth = getTerminal().getWidth();
-        int lines = getCursorPosition() / termwidth;
-        count = moveCursor(-1 * num) * -1;
+        int count = - moveCursor(-num);
+        int clear = wcwidth(buf.buffer, buf.cursor, buf.cursor + count, getCursorPosition());
         buf.buffer.delete(buf.cursor, buf.cursor + count);
-        if (getCursorPosition() / termwidth != lines) {
-            if (terminal.isAnsiSupported()) {
-                // debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
-                printAnsiSequence("K");
-                // if cursor+num wraps, then we need to clear the line(s) below too
-                // last char printed is one pos less than cursor so we subtract
-                // one
-/*
-                // TODO: fixme (does not work - test with reverse search with wrapping line and CTRL-E)
-                int endCol = (getCursorPosition() + num - 1) % termwidth;
-                int curCol = getCursorPosition() % termwidth;
-                if (endCol < curCol) lines++;
-                for (int i = 1; i < lines; i++) {
-                    printAnsiSequence("B");
-                    printAnsiSequence("2K");
-                }
-                for (int i = 1; i < lines; i++) {
-                    printAnsiSequence("A");
-                }
-                return count;
-*/
-            }
-        }
-        drawBuffer(count);
-
+
+        drawBuffer(clear);
         return count;
     }
 
@@ -1080,7 +1120,7 @@
             case FORWARD_CHAR:
             case END_OF_LINE:
             case VI_MATCH:
-            case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+            case VI_BEGINNING_OF_LINE_OR_ARG_DIGIT:
             case VI_ARG_DIGIT:
             case VI_PREV_WORD:
             case VI_END_WORD:
@@ -1103,7 +1143,6 @@
      * Deletes the previous character from the cursor position
      * @param count number of times to do it.
      * @return true if it was done.
-     * @throws IOException
      */
     private boolean viRubout(int count) throws IOException {
         boolean ok = true;
@@ -1118,7 +1157,6 @@
      * 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
-     * @throws IOException
      */
     private boolean viDelete(int count) throws IOException {
         boolean ok = true;
@@ -1135,7 +1173,6 @@
      * @param count The number of times to repeat
      * @return true if it completed successfully, false if not all
      *   case changes could be completed.
-     * @throws IOException
      */
     private boolean viChangeCase(int count) throws IOException {
         boolean ok = true;
@@ -1164,7 +1201,6 @@
      * @param count Number of times to perform the action
      * @param c The character to change to
      * @return Whether or not there were problems encountered
-     * @throws IOException
      */
     private boolean viChangeChar(int count, int c) throws IOException {
         // EOF, ESC, or CTRL-C aborts.
@@ -1194,7 +1230,6 @@
      *
      * @param count number of iterations
      * @return true if the move was successful, false otherwise
-     * @throws IOException
      */
     private boolean viPreviousWord(int count) throws IOException {
         boolean ok = true;
@@ -1230,7 +1265,6 @@
      *    (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
-     * @throws IOException
      */
     private boolean viDeleteTo(int startPos, int endPos, boolean isChange) throws IOException {
         if (startPos == endPos) {
@@ -1267,7 +1301,6 @@
      * @param startPos The starting position from which to yank
      * @param endPos The ending position to which to yank
      * @return true if the yank succeeded
-     * @throws IOException
      */
     private boolean viYankTo(int startPos, int endPos) throws IOException {
         int cursorPos = startPos;
@@ -1299,7 +1332,6 @@
      *
      * @param count Number of times to perform the operation.
      * @return true if it worked, false otherwise
-     * @throws IOException
      */
     private boolean viPut(int count) throws IOException {
         if (yankBuffer.length () == 0) {
@@ -1321,7 +1353,6 @@
      * @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
-     * @throws IOException
      */
     private boolean viCharSearch(int count, int invokeChar, int ch) throws IOException {
         if (ch < 0 || invokeChar < 0) {
@@ -1421,7 +1452,7 @@
         return ok;
     }
 
-    private char switchCase(char ch) {
+    private static char switchCase(char ch) {
         if (Character.isUpperCase(ch)) {
             return Character.toLowerCase(ch);
         }
@@ -1445,7 +1476,6 @@
      *
      * @param count number of iterations
      * @return true if the move was successful, false otherwise
-     * @throws IOException
      */
     private boolean viNextWord(int count) throws IOException {
         int pos = buf.cursor;
@@ -1483,7 +1513,6 @@
      *
      * @param count Number of times to repeat the action
      * @return true if it worked.
-     * @throws IOException
      */
     private boolean viEndWord(int count) throws IOException {
         int pos = buf.cursor;
@@ -1541,7 +1570,6 @@
      *
      * @param count Number of times to perform the operation
      * @return true if it worked, false if you tried to delete too many words
-     * @throws IOException
      */
     private boolean unixWordRubout(int count) throws IOException {
         boolean success = true;
@@ -1581,7 +1609,7 @@
     }
 
     private String insertComment(boolean isViMode) throws IOException {
-        String comment = this.getCommentBegin ();
+        String comment = this.getCommentBegin();
         setCursorPosition(0);
         putString(comment);
         if (isViMode) {
@@ -1591,34 +1619,7 @@
     }
 
     /**
-     * Similar to putString() but allows the string to be repeated a specific
-     * number of times, allowing easy support of vi digit arguments to a given
-     * command. The string is placed as the current cursor position.
-     *
-     * @param count The count of times to insert the string.
-     * @param str The string to insert
-     * @return true if the operation is a success, false otherwise
-     * @throws IOException
-     */
-    private boolean insert(int count, final CharSequence str) throws IOException {
-        for (int i = 0; i < count; i++) {
-            buf.write(str);
-            if (mask == null) {
-                // no masking
-                print(str);
-            } else if (mask == NULL_MASK) {
-                // don't print anything
-            } else {
-                print(mask, str.length());
-            }
-        }
-        drawBuffer();
-        return true;
-    }
-
-    /**
      * Implements vi search ("/" or "?").
-     * @throws IOException
      */
     @SuppressWarnings("fallthrough")
     private int viSearch(char searchChar) throws IOException {
@@ -1793,18 +1794,19 @@
     }
 
     private void insertClose(String s) throws IOException {
-         putString(s);
-         int closePosition = buf.cursor;
-
-         moveCursor(-1);
-         viMatch();
-
-
-         if (in.isNonBlockingEnabled()) {
+        putString(s);
+        int closePosition = buf.cursor;
+
+        moveCursor(-1);
+        viMatch();
+
+
+        if (in.isNonBlockingEnabled()) {
             in.peek(parenBlinkTimeout);
-         }
-
-         setCursorPosition(closePosition);
+        }
+
+        setCursorPosition(closePosition);
+        flush();
     }
 
     /**
@@ -1813,7 +1815,6 @@
      * 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.
-     * @throws IOException
      */
     private boolean viMatch() throws IOException {
         int pos        = buf.cursor;
@@ -1854,6 +1855,7 @@
             ++pos;
 
         setCursorPosition(pos);
+        flush();
         return true;
     }
 
@@ -1864,7 +1866,7 @@
      * @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 int getBracketType (char ch) {
+    private static int getBracketType (char ch) {
         switch (ch) {
             case '[': return  1;
             case ']': return -1;
@@ -1976,7 +1978,6 @@
      * @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).
-     * @throws IOException
      */
     private boolean transposeChars(int count) throws IOException {
         for (; count > 0; --count) {
@@ -2021,7 +2022,6 @@
      * complete and is returned.
      *
      * @return The completed line of text.
-     * @throws IOException
      */
     public String accept() throws IOException {
         moveToEnd();
@@ -2076,75 +2076,65 @@
         // + buf.cursor + " => " + (buf.cursor + where) + ")");
         buf.cursor += where;
 
-        if (terminal.isAnsiSupported()) {
+        int i0;
+        int i1;
+        if (mask == null) {
             if (where < 0) {
-                back(Math.abs(where));
+                i1 = promptLen + wcwidth(buf.buffer, 0, buf.cursor, promptLen);
+                i0 = i1 + wcwidth(buf.buffer, buf.cursor, buf.cursor - where, i1);
             } else {
-                int width = getTerminal().getWidth();
-                int cursor = getCursorPosition();
-                int oldLine = (cursor - where) / width;
-                int newLine = cursor / width;
-                if (newLine > oldLine) {
-                    printAnsiSequence((newLine - oldLine) + "B");
-                }
-                printAnsiSequence(1 +(cursor % width) + "G");
+                i0 = promptLen + wcwidth(buf.buffer, 0, buf.cursor - where, promptLen);
+                i1 = i0 + wcwidth(buf.buffer, buf.cursor - where, buf.cursor, i0);
             }
-//            flush();
+        } else if (mask != NULL_MASK) {
+            i1 = promptLen + buf.cursor;
+            i0 = i1 - where;
+        } else {
             return;
         }
-
-        char c;
-
-        if (where < 0) {
-            int len = 0;
-            for (int i = buf.cursor; i < buf.cursor - where; i++) {
-                if (buf.buffer.charAt(i) == '\t') {
-                    len += TAB_WIDTH;
-                }
-                else {
-                    len++;
+        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");
                 }
             }
-
-            char chars[] = new char[len];
-            Arrays.fill(chars, BACKSPACE);
-            out.write(chars);
-
-            return;
+        } else if (l0 < l1) {
+            tputs("carriage_return");
+            rawPrint('\n', l1 - l0);
+            c0 = 0;
         }
-        else if (buf.cursor == 0) {
-            return;
+        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");
+                }
+            }
         }
-        else if (mask != null) {
-            c = mask;
-        }
-        else {
-            print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
-            return;
-        }
-
-        // null character mask: don't output anything
-        if (mask == NULL_MASK) {
-            return;
-        }
-
-        print(c, Math.abs(where));
-    }
-
-    // FIXME: replace() is not used
-
-    public final boolean replace(final int num, final String replacement) {
-        buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
-        try {
-            moveCursor(-num);
-            drawBuffer(Math.max(0, num - replacement.length()));
-            moveCursor(replacement.length());
-        }
-        catch (IOException e) {
-            e.printStackTrace();
-            return false;
-        }
-        return true;
+        cursorOk = true;
     }
 
     /**
@@ -2152,7 +2142,17 @@
      *
      * @return the character, or -1 if an EOF is received.
      */
-    public final int readCharacter() throws IOException {
+    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);
@@ -2160,6 +2160,20 @@
             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;
     }
@@ -2174,81 +2188,158 @@
         }
 
         // otherwise, clear
-        int num = countEchoCharacters(c);
-        back(num);
+        int pos = getCursorPosition();
+        int num = wcwidth(c, pos);
+        moveCursorFromTo(pos + num, pos);
         drawBuffer(num);
 
         return num;
     }
 
-    private int countEchoCharacters(final int c) {
-        // tabs as special: we need to determine the number of spaces
-        // to cancel based on what out current cursor position is
-        if (c == 9) {
-            int tabStop = 8; // will this ever be different?
-            int position = getCursorPosition();
-
-            return tabStop - (position % tabStop);
+    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 getPrintableCharacters(c).length();
+        return c;
     }
 
     /**
-     * Return the number of characters that will be printed when the specified
-     * character is echoed to the screen
+     * Read from the input stream and decode an operation from the key map.
      *
-     * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
+     * 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
      */
-    private StringBuilder getPrintableCharacters(final int ch) {
-        StringBuilder sbuff = new StringBuilder();
-
-        if (ch >= 32) {
-            if (ch < 127) {
-                sbuff.append(ch);
+    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;
             }
-            else if (ch == 127) {
-                sbuff.append('^');
-                sbuff.append('?');
+            opBuffer.appendCodePoint(c);
+
+            if (recording) {
+                macro += new String(Character.toChars(c));
             }
-            else {
-                sbuff.append('M');
-                sbuff.append('-');
-
-                if (ch >= (128 + 32)) {
-                    if (ch < (128 + 127)) {
-                        sbuff.append((char) (ch - 128));
+
+            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;
                     }
-                    else {
-                        sbuff.append('^');
-                        sbuff.append('?');
+                    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);
                     }
                 }
-                else {
-                    sbuff.append('^');
-                    sbuff.append((char) (ch - 128 + 64));
-                }
             }
-        }
-        else {
-            sbuff.append('^');
-            sbuff.append((char) (ch + 64));
-        }
-
-        return sbuff;
+
+        } while (o == null || o instanceof KeyMap);
+
+        return o;
     }
 
-    public final int readCharacter(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()) < 0) {
-            // nothing
-        }
-
-        return c;
+    public String getLastBinding() {
+        return opBuffer.toString();
     }
 
     //
@@ -2281,6 +2372,18 @@
     }
 
     /**
+     * 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
@@ -2309,9 +2412,10 @@
      * @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 {
+    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
@@ -2321,7 +2425,7 @@
         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;
+        this.mask = mask != null ? mask : this.echoCharacter;
         if (prompt != null) {
             setPrompt(prompt);
         }
@@ -2330,12 +2434,17 @@
         }
 
         try {
+            if (buffer != null) {
+                buf.write(buffer);
+            }
+
             if (!terminal.isSupported()) {
                 beforeReadLine(prompt, mask);
             }
 
-            if (prompt != null && prompt.length() > 0) {
-                out.write(prompt);
+            if (buffer != null && buffer.length() > 0
+                    || prompt != null && prompt.length() > 0) {
+                drawLine();
                 out.flush();
             }
 
@@ -2371,9 +2480,12 @@
                 return readLineSimple();
             }
 
-            if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
-                ((UnixTerminal) terminal).disableInterruptCharacter();
+            if (handleUserInterrupt) {
+                terminal.disableInterruptCharacter();
             }
+            if (handleLitteralNext && (terminal instanceof UnixTerminal)) {
+                ((UnixTerminal) terminal).disableLitteralNextCharacter();
+            }
 
             String originalPrompt = this.prompt;
 
@@ -2381,110 +2493,15 @@
 
             boolean success = true;
 
-            StringBuilder sb = new StringBuilder();
             while (true) {
-                int c = pushBackChar.isEmpty() ? readCharacter() : pushBackChar.pop ();
-                if (c == -1) {
+
+                Object o = readBinding(getKeys());
+                if (o == null) {
                     return null;
                 }
-                sb.appendCodePoint(c);
-
-                if (recording) {
-                    macro += new String(new int[]{c}, 0, 1);
-                }
-
-                Object o = getKeys().getBound( sb );
-                /*
-                 * 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) {
-                    sb.setLength( sb.length() - 1);
-                    sb.append( Character.toLowerCase( (char) c ));
-                    o = getKeys().getBound( sb );
-                }
-
-                /*
-                 * 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 == 27
-                            && pushBackChar.isEmpty()
-                            && in.isNonBlockingEnabled()
-                            && in.peek(escapeTimeout) == -2) {
-                        o = ((KeyMap) o).getAnotherKey();
-                        if (o == null || o instanceof KeyMap) {
-                            continue;
-                        }
-                        sb.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 && sb.length() > 0 ) {
-                    c = sb.charAt( sb.length() - 1 );
-                    sb.setLength( sb.length() - 1 );
-                    Object o2 = getKeys().getBound( sb );
-                    if ( o2 instanceof KeyMap ) {
-                        o = ((KeyMap) o2).getAnotherKey();
-                        if ( o == null ) {
-                            continue;
-                        } else {
-                            pushBackChar.push( (char) c );
-                        }
-                    }
-                }
-
-                if ( o == null ) {
-                    continue;
+                int c = 0;
+                if (opBuffer.length() > 0) {
+                    c = opBuffer.codePointBefore(opBuffer.length());
                 }
                 Log.trace("Binding: ", o);
 
@@ -2495,7 +2512,7 @@
                     for (int i = 0; i < macro.length(); i++) {
                         pushBackChar.push(macro.charAt(macro.length() - 1 - i));
                     }
-                    sb.setLength( 0 );
+                    opBuffer.setLength(0);
                     continue;
                 }
 
@@ -2520,7 +2537,7 @@
                         } catch (InvocationTargetException ex ) {
                             Log.error("Exception while running registered action", ex);
                         }
-                        sb.setLength( 0 );
+                        opBuffer.setLength(0);
                         continue;
                     }
                 } catch (ReflectiveOperationException ex) {
@@ -2529,10 +2546,14 @@
 
                 if (o instanceof Runnable) {
                     ((Runnable) o).run();
-                    sb.setLength(0);
+                    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
@@ -2540,11 +2561,13 @@
                 // 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.buffer.append(searchTerm);
+                            buf.write(originalBuffer.buffer);
+                            buf.cursor = originalBuffer.cursor;
                             break;
 
                         case REVERSE_SEARCH_HISTORY:
@@ -2596,6 +2619,9 @@
                                 // 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;
                     }
@@ -2685,7 +2711,7 @@
                                     success = complete();
                                 }
                                 else {
-                                    putString(sb);
+                                    putString(opBuffer);
                                 }
                                 break;
 
@@ -2723,7 +2749,7 @@
                                 break;
 
                             case SELF_INSERT:
-                                putString(sb);
+                                putString(opBuffer);
                                 break;
 
                             case ACCEPT_LINE:
@@ -2884,6 +2910,9 @@
                                 break;
 
                             case REVERSE_SEARCH_HISTORY:
+                                originalBuffer = new CursorBuffer();
+                                originalBuffer.write(buf.buffer);
+                                originalBuffer.cursor = buf.cursor;
                                 if (searchTerm != null) {
                                     previousSearchTerm = searchTerm.toString();
                                 }
@@ -2903,6 +2932,9 @@
                                 break;
 
                             case FORWARD_SEARCH_HISTORY:
+                                originalBuffer = new CursorBuffer();
+                                originalBuffer.write(buf.buffer);
+                                originalBuffer.cursor = buf.cursor;
                                 if (searchTerm != null) {
                                     previousSearchTerm = searchTerm.toString();
                                 }
@@ -2951,14 +2983,14 @@
 
                             case END_KBD_MACRO:
                                 recording = false;
-                                macro = macro.substring(0, macro.length() - sb.length());
+                                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));
                                 }
-                                sb.setLength( 0 );
+                                opBuffer.setLength(0);
                                 break;
 
                             case VI_EDITING_MODE:
@@ -3031,20 +3063,20 @@
                                 break;
 
                             case VI_SEARCH:
-                                int lastChar = viSearch(sb.charAt (0));
+                                int lastChar = viSearch(opBuffer.charAt(0));
                                 if (lastChar != -1) {
                                     pushBackChar.push((char)lastChar);
                                 }
                                 break;
 
                             case VI_ARG_DIGIT:
-                                repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+                                repeatCount = (repeatCount * 10) + opBuffer.charAt(0) - '0';
                                 isArgDigit = true;
                                 break;
 
-                            case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+                            case VI_BEGINNING_OF_LINE_OR_ARG_DIGIT:
                                 if (repeatCount > 0) {
-                                    repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+                                    repeatCount = (repeatCount * 10) + opBuffer.charAt(0) - '0';
                                     isArgDigit = true;
                                 }
                                 else {
@@ -3164,6 +3196,18 @@
                                 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;
                         }
@@ -3200,6 +3244,7 @@
                         }
 
                         if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
+                            originalBuffer = null;
                             previousSearchTerm = "";
                             searchTerm = null;
                             searchIndex = -1;
@@ -3209,7 +3254,8 @@
                 if (!success) {
                     beep();
                 }
-                sb.setLength( 0 );
+                opBuffer.setLength(0);
+
                 flush();
             }
         }
@@ -3217,21 +3263,19 @@
             if (!terminal.isSupported()) {
                 afterReadLine();
             }
-            if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
-                ((UnixTerminal) terminal).enableInterruptCharacter();
+            if (handleUserInterrupt) {
+                terminal.enableInterruptCharacter();
             }
         }
     }
     //where:
         private Pattern CURSOR_COLUMN_PATTERN =
                 Pattern.compile("(?<prefix>.*)\033\\[[0-9]+;(?<column>[0-9]+)R", Pattern.DOTALL);
-        private Stack<Character> pushBackChar = new Stack<Character>();
 
     /**
      * Read a line for unsupported terminals.
      */
     private String readLineSimple() throws IOException {
-        StringBuilder buff = new StringBuilder();
 
         if (skipLF) {
             skipLF = false;
@@ -3239,28 +3283,28 @@
             int i = readCharacter();
 
             if (i == -1 || i == '\r') {
-                return buff.toString();
+                return finishBuffer();
             } else if (i == '\n') {
                 // ignore
             } else {
-                buff.append((char) i);
+                buf.buffer.append((char) i);
             }
         }
 
         while (true) {
             int i = readCharacter();
 
-            if (i == -1 && buff.length() == 0) {
+            if (i == -1 && buf.buffer.length() == 0) {
               return null;
             }
 
             if (i == -1 || i == '\n') {
-                return buff.toString();
+                return finishBuffer();
             } else if (i == '\r') {
                 skipLF = true;
-                return buff.toString();
+                return finishBuffer();
             } else {
-                buff.append((char) i);
+                buf.buffer.append((char) i);
             }
         }
     }
@@ -3426,7 +3470,6 @@
      * @param next If true, move forward
      * @param count The number of entries to move
      * @return true if the move was successful
-     * @throws IOException
      */
     private boolean moveHistory(final boolean next, int count) throws IOException {
         boolean ok = true;
@@ -3456,89 +3499,89 @@
     // Printing
     //
 
-    public static final String CR = Configuration.getLineSeparator();
-
-    /**
-     * Output the specified character to the output stream without manipulating the current buffer.
-     */
-    private void print(final int c) throws IOException {
-        if (c == '\t') {
-            char chars[] = new char[TAB_WIDTH];
-            Arrays.fill(chars, ' ');
-            out.write(chars);
-            return;
-        }
-
-        out.write(c);
-    }
-
     /**
      * Output the specified characters to the output stream without manipulating the current buffer.
      */
-    private void print(final char... buff) throws IOException {
-        int len = 0;
-        for (char c : buff) {
+    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') {
-                len += TAB_WIDTH;
-            }
-            else {
-                len++;
-            }
-        }
-
-        char chars[];
-        if (len == buff.length) {
-            chars = buff;
-        }
-        else {
-            chars = new char[len];
-            int pos = 0;
-            for (char c : buff) {
-                if (c == '\t') {
-                    Arrays.fill(chars, pos, pos + TAB_WIDTH, ' ');
-                    pos += TAB_WIDTH;
+                int nb = nextTabStop(cursorPos);
+                cursorPos += nb;
+                while (nb-- > 0) {
+                    out.write(' ');
                 }
-                else {
-                    chars[pos] = c;
-                    pos++;
+            } 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;
                 }
             }
         }
-
-        out.write(chars);
-    }
-
-    private void print(final char c, final int num) throws IOException {
-        if (num == 1) {
-            print(c);
-        }
-        else {
-            char[] chars = new char[num];
-            Arrays.fill(chars, c);
-            print(chars);
-        }
+        cursorOk = false;
+        return cursorPos;
     }
 
     /**
      * Output the specified string to the output stream (but not the buffer).
      */
-    public final void print(final CharSequence s) throws IOException {
-        print(checkNotNull(s).toString().toCharArray());
+    public void print(final CharSequence s) throws IOException {
+        rawPrint(s.toString());
     }
 
-    public final void println(final CharSequence s) throws IOException {
-        print(checkNotNull(s).toString().toCharArray());
+    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 final void println() throws IOException {
-        print(CR);
-//        flush();
+    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
     //
@@ -3548,7 +3591,7 @@
      *
      * @return true if successful
      */
-    public final boolean delete() throws IOException {
+    public boolean delete() throws IOException {
         if (buf.cursor == buf.buffer.length()) {
           return false;
         }
@@ -3573,7 +3616,9 @@
         }
 
         int num = len - cp;
-        clearAhead(num, 0);
+        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);
@@ -3619,16 +3664,9 @@
      * Clear the screen by issuing the ANSI "clear screen" code.
      */
     public boolean clearScreen() throws IOException {
-        if (!terminal.isAnsiSupported()) {
-            return false;
+        if (!tputs("clear_screen")) {
+            println();
         }
-
-        // send the ANSI code to clear the screen
-        printAnsiSequence("2J");
-
-        // then send the ANSI code to go to position 1,1
-        printAnsiSequence("1;1H");
-
         return true;
     }
 
@@ -3637,9 +3675,10 @@
      */
     public void beep() throws IOException {
         if (bellEnabled) {
-            print(KEYBOARD_BELL);
-            // need to flush so the console actually beeps
-            flush();
+            if (tputs("bell")) {
+                // need to flush so the console actually beeps
+                flush();
+            }
         }
     }
 
@@ -3727,12 +3766,6 @@
 //    }
 
     //disabled to avoid dependency on java.desktop:
-//    //
-//    // Triggered Actions
-//    //
-//
-//    private final Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
-//
 //    /**
 //     * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
 //     * <p/>
@@ -3740,7 +3773,7 @@
 //     * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
 //     */
 //    public void addTriggeredAction(final char c, final ActionListener listener) {
-//        triggeredActions.put(c, listener);
+//        getKeys().bind(Character.toString(c), listener);
 //    }
 
     //
@@ -3760,7 +3793,9 @@
 
         int maxWidth = 0;
         for (CharSequence item : items) {
-            maxWidth = Math.max(maxWidth, item.length());
+            // 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);
@@ -3774,10 +3809,12 @@
         }
 
         StringBuilder buff = new StringBuilder();
+        int realLength = 0;
         for (CharSequence item : items) {
-            if ((buff.length() + maxWidth) > width) {
-                println(buff);
+            if ((realLength + maxWidth) > width) {
+                rawPrintln(buff.toString());
                 buff.setLength(0);
+                realLength = 0;
 
                 if (--showLines == 0) {
                     // Overflow
@@ -3793,7 +3830,7 @@
                         showLines = height - 1;
                     }
 
-                    back(resources.getString("DISPLAY_MORE").length());
+                    tputs("carriage_return");
                     if (c == 'q') {
                         // cancel
                         break;
@@ -3803,13 +3840,15 @@
 
             // NOTE: toString() is important here due to AnsiString being retarded
             buff.append(item.toString());
-            for (int i = 0; i < (maxWidth - item.length()); i++) {
+            int strippedItemLength = wcwidth(Ansi.stripAnsi(item.toString()), 0);
+            for (int i = 0; i < (maxWidth - strippedItemLength); i++) {
                 buff.append(' ');
             }
+            realLength += maxWidth;
         }
 
         if (buff.length() > 0) {
-            println(buff);
+            rawPrintln(buff.toString());
         }
     }
 
@@ -4018,7 +4057,7 @@
      * @param c     The character to test
      * @return      True if it is a delimiter
      */
-    private boolean isDelimiter(final char c) {
+    private static boolean isDelimiter(final char c) {
         return !Character.isLetterOrDigit(c);
     }
 
@@ -4031,15 +4070,17 @@
      * @param c The character to check
      * @return true if the character is a whitespace
      */
-    private boolean isWhitespace(final char c) {
+    private static boolean isWhitespace(final char c) {
         return Character.isWhitespace (c);
     }
 
-    private void printAnsiSequence(String sequence) throws IOException {
-        print(27);
-        print('[');
-        print(sequence);
-        flush(); // helps with step debugging
+    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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -92,7 +92,7 @@
         cursor += str.length();
 
         if (isOverTyping() && cursor < buffer.length()) {
-            buffer.delete(cursor, (cursor + str.length()));
+            buffer.delete(cursor, cursor + str.length());
         }
     }
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -33,20 +33,19 @@
     private Object[] mapping = new Object[KEYMAP_LENGTH];
     private Object anotherKey = null;
     private String name;
-    private boolean isViKeyMap;
 
-    public KeyMap(String name, boolean isViKeyMap) {
-        this(name, new Object[KEYMAP_LENGTH], isViKeyMap);
+    public KeyMap(String name) {
+        this(name, new Object[KEYMAP_LENGTH]);
     }
 
-    protected KeyMap(String name, Object[] mapping, boolean isViKeyMap) {
+    @Deprecated
+    public KeyMap(String name, boolean unused) {
+        this(name);
+    }
+
+    protected KeyMap(String name, Object[] mapping) {
         this.mapping = mapping;
         this.name = name;
-        this.isViKeyMap = isViKeyMap;
-    }
-
-    public boolean isViKeyMap() {
-        return isViKeyMap;
     }
 
     public String getName() {
@@ -110,7 +109,7 @@
                 }
                 if (i < keySeq.length() - 1) {
                     if (!(map.mapping[c] instanceof KeyMap)) {
-                        KeyMap m = new KeyMap("anonymous", false);
+                        KeyMap m = new KeyMap("anonymous");
                         if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
                             m.anotherKey = map.mapping[c];
                         }
@@ -239,11 +238,11 @@
         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);
-        keyMaps.put("vi", viIns);
 
         return keyMaps;
     }
@@ -290,7 +289,7 @@
             map[i] = Operation.SELF_INSERT;
         }
         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
-        return new KeyMap(EMACS, map, false);
+        return new KeyMap(EMACS, map);
     }
 
     public static final char CTRL_D = (char) 4;
@@ -323,7 +322,7 @@
         }
         map['e'] = Operation.CALL_LAST_KBD_MACRO;
         map[DELETE] = Operation.KILL_LINE;
-        return new KeyMap(EMACS_CTLX, map, false);
+        return new KeyMap(EMACS_CTLX, map);
     }
 
     public static KeyMap emacsMeta() {
@@ -364,7 +363,7 @@
         map['y'] = Operation.YANK_POP;
         map['~'] = Operation.TILDE_EXPAND;
         map[DELETE] = Operation.BACKWARD_KILL_WORD;
-        return new KeyMap(EMACS_META, map, false);
+        return new KeyMap(EMACS_META, map);
     }
 
     public static KeyMap viInsertion() {
@@ -409,7 +408,7 @@
             map[i] = Operation.SELF_INSERT;
         }
         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
-        return new KeyMap(VI_INSERT, map, false);
+        return new KeyMap(VI_INSERT, map);
     }
 
     public static KeyMap viMovement() {
@@ -485,7 +484,7 @@
                         /* TODO */
                         Operation.VI_REDO,                  /* . */
                         Operation.VI_SEARCH,                /* / */
-                        Operation.VI_BEGNNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
+                        Operation.VI_BEGINNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
                         Operation.VI_ARG_DIGIT,             /* 1 */
                         Operation.VI_ARG_DIGIT,             /* 2 */
                         Operation.VI_ARG_DIGIT,             /* 3 */
@@ -573,6 +572,6 @@
         for (int i = 128; i < 256; i++) {
             map[i] = null;
         }
-        return new KeyMap(VI_MOVE, map, false);
+        return new KeyMap(VI_MOVE, map);
     }
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2013, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -38,7 +38,7 @@
     }
 
     /**
-     * Creates a new kill ring of the default size. {@see DEFAULT_SIZE}.
+     * Creates a new kill ring of the default size. See {@link #DEFAULT_SIZE}.
      */
     public KillRing() {
         this(DEFAULT_SIZE);
@@ -152,7 +152,7 @@
     private void prev() {
         head--;
         if (head == -1) {
-            int x = (slots.length - 1);
+            int x = slots.length - 1;
             for (; x >= 0; x--) {
                 if (slots[x] != null) {
                     break;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -81,6 +81,7 @@
     POSSIBLE_COMPLETIONS,
     PREVIOUS_HISTORY,
     QUOTED_INSERT,
+    QUIT,
     RE_READ_INIT_FILE,
     REDRAW_CURRENT_LINE,
     REVERSE_SEARCH_HISTORY,
@@ -156,5 +157,5 @@
     VI_NEXT_HISTORY,
     VI_PREVIOUS_HISTORY,
     VI_INSERT_COMMENT,
-    VI_BEGNNING_OF_LINE_OR_ARG_DIGIT,
+    VI_BEGINNING_OF_LINE_OR_ARG_DIGIT,
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/WCWidth.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,158 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AnsiStringsCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -144,7 +144,7 @@
                 return -1;
             }
 
-            if (subCandidates.size() == 0) {
+            if (!subCandidates.contains(arg)) {
                 return -1;
             }
         }
@@ -326,10 +326,6 @@
 
         /**
          * Check if this character is a valid escape char (i.e. one that has not been escaped)
-         *
-         * @param buffer
-         * @param pos
-         * @return
          */
         public boolean isEscapeChar(final CharSequence buffer, final int pos) {
             if (pos < 0) {
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -10,6 +10,7 @@
 
 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;
@@ -33,6 +34,25 @@
 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
@@ -42,7 +62,13 @@
 
         // if there is only one completion, then fill in the buffer
         if (candidates.size() == 1) {
-            CharSequence value = candidates.get(0);
+            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())) {
@@ -90,7 +116,8 @@
 
         if (distinct.size() > reader.getAutoprintThreshold()) {
             //noinspection StringConcatenation
-            reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size()));
+            reader.println();
+            reader.print(Messages.DISPLAY_CANDIDATES.format(distinct.size()));
             reader.flush();
 
             int c;
@@ -142,10 +169,25 @@
             return null;
         }
 
+        if (candidates.size() == 1) {
+            return candidates.get(0).toString();
+        }
+
         // convert to an array for speed
-        String[] strings = candidates.toArray(new String[candidates.size()]);
+        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;
+            }
+        }
 
-        String first = strings[0];
         StringBuilder candidate = new StringBuilder();
 
         for (int i = 0; i < first.length(); i++) {
@@ -163,9 +205,9 @@
     /**
      * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
      */
-    private boolean startsWith(final String starts, final String[] candidates) {
+    private static boolean startsWith(final String starts, final String[] candidates) {
         for (String candidate : candidates) {
-            if (!candidate.startsWith(starts)) {
+            if (!candidate.toLowerCase().startsWith(starts.toLowerCase())) {
                 return false;
             }
         }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2002-2012, the original author or authors.
+# Copyright (c) 2002-2016, the original author or authors.
 #
 # This software is distributable under the BSD license. See the terms of the
 # BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -20,10 +20,14 @@
     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(n.name().toLowerCase());
+            this.getStrings().add(toLowerCase ? n.name().toLowerCase() : n.name());
         }
     }
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -61,10 +61,6 @@
             }
         }
 
-        if (candidates.size() == 1) {
-            candidates.set(0, candidates.get(0) + " ");
-        }
-
         return candidates.isEmpty() ? -1 : 0;
     }
 }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -38,8 +38,29 @@
 {
     private final File file;
 
+    /**
+     * Load a history file into memory, truncating to default max size.
+     */
     public FileHistory(final File file) throws IOException {
-        this.file = checkNotNull(file);
+        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);
     }
 
@@ -51,7 +72,15 @@
         checkNotNull(file);
         if (file.exists()) {
             Log.trace("Loading history from: ", file);
-            load(new FileReader(file));
+            FileReader reader = null;
+            try{
+                reader = new FileReader(file);
+                load(reader);
+            } finally{
+                if(reader != null){
+                    reader.close();
+                }
+            }
         }
     }
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -261,8 +261,6 @@
 
     /**
      * Move to the specified index in the history
-     * @param index
-     * @return
      */
     public boolean moveTo(int index) {
         index -= offset;
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -12,6 +12,7 @@
 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;
@@ -75,11 +76,15 @@
         try {
             Class<?> type = Class.forName(mainClass);
             Method method = type.getMethod("main", String[].class);
-            method.invoke(null);
+            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();
+            }
         }
     }
 
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/AnsiInterpretingOutputStream.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,162 @@
+/*
+ * 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;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Ansi.java	Fri Jun 01 13:04:30 2018 +0200
@@ -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.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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -12,8 +12,10 @@
 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;
 
@@ -48,9 +50,12 @@
         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) {
-            // debug here instead of warn, as this can happen normally if default jline.rc file is missing
-            Log.debug("Unable to read configuration from: ", url, e);
+            Log.warn("Unable to read configuration from: ", url, e);
         }
         return props;
     }
@@ -138,6 +143,10 @@
         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) {
@@ -197,25 +206,38 @@
         return getOsName().startsWith("windows");
     }
 
-    // FIXME: Sort out use of property access of file.encoding in InputStreamReader, consolidate should configuration access here
+    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_CTYPE environment variable, then the input.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() {
-        // LC_CTYPE is usually in the form en_US.UTF-8
-        String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
-        if (envEncoding != null) {
-            return envEncoding;
+        // 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 System.getProperty("input.encoding", Charset.defaultCharset().name());
+        return getString("input.encoding", Charset.defaultCharset().name());
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Curses.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,341 @@
+/*
+ * 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());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InfoCmp.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,591 @@
+/*
+ * 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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InputStreamReader.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -49,8 +49,6 @@
 
     private boolean endOfInput = false;
 
-    String encoding;
-
     CharsetDecoder decoder;
 
     ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
@@ -67,9 +65,7 @@
     public InputStreamReader(InputStream in) {
         super(in);
         this.in = in;
-        // FIXME: This should probably use Configuration.getFileEncoding()
-        encoding = System.getProperty("file.encoding", "ISO8859_1"); //$NON-NLS-1$//$NON-NLS-2$
-        decoder = Charset.forName(encoding).newDecoder().onMalformedInput(
+        decoder = Charset.defaultCharset().newDecoder().onMalformedInput(
                 CodingErrorAction.REPLACE).onUnmappableCharacter(
                 CodingErrorAction.REPLACE);
         bytes.limit(0);
@@ -172,7 +168,7 @@
         if (!isOpen()) {
             return null;
         }
-        return encoding;
+        return decoder.charset().name();
     }
 
     /**
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -8,7 +8,10 @@
  */
 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;
 
@@ -16,6 +19,7 @@
  * 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
@@ -31,14 +35,14 @@
         ERROR
     }
 
-    @SuppressWarnings({"StringConcatenation"})
-    public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
+    public static final boolean TRACE = Configuration.getBoolean(Log.class.getName() + ".trace");
 
-    @SuppressWarnings({"StringConcatenation"})
-    public static final boolean DEBUG = TRACE || Boolean.getBoolean(Log.class.getName() + ".debug");
+    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;
     }
@@ -71,6 +75,10 @@
 
     @TestAccessible
     static void log(final Level level, final Object... messages) {
+        if (useJul) {
+            logWithJul(level, messages);
+            return;
+        }
         //noinspection SynchronizeOnNonFinalField
         synchronized (output) {
             output.format("[%s] ", level);
@@ -91,6 +99,43 @@
         }
     }
 
+    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);
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -111,7 +111,6 @@
      * @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
      */
     public int peek(long timeout) throws IOException {
         if (!nonBlockingEnabled || isShutdown) {
@@ -127,7 +126,6 @@
      * @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
      */
     public int read(long timeout) throws IOException {
         if (!nonBlockingEnabled || isShutdown) {
@@ -143,7 +141,6 @@
      * @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
      */
     private synchronized int read(long timeout, boolean isPeek) throws IOException {
         /*
@@ -177,7 +174,7 @@
                 notify();
             }
 
-            boolean isInfinite = (timeout <= 0L);
+            boolean isInfinite = timeout <= 0L;
 
             /*
              * So the thread is currently doing the reading for us. So
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
@@ -13,7 +13,10 @@
 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;
 
@@ -26,6 +29,7 @@
  * @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
@@ -38,21 +42,72 @@
 
     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 {
-        sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
-        shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
-        initialConfig = get("-g").trim();
-        config = get("-a");
-        configLastFetched = System.currentTimeMillis();
+        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);
 
@@ -62,6 +117,19 @@
         }
     }
 
+    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;
     }
@@ -71,13 +139,25 @@
     }
 
     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.
@@ -88,6 +168,21 @@
      */
     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
@@ -100,7 +195,7 @@
             }
             Log.debug("Failed to query stty ", name, "\n", e);
             if (config == null) {
-                return -1;
+                return false;
             }
         }
 
@@ -108,8 +203,7 @@
         if (currentTime - configLastFetched > 1000) {
             configLastFetched = currentTime;
         }
-
-        return getProperty(name, config);
+        return true;
     }
 
     /**
@@ -121,7 +215,7 @@
      * @param stty string resulting of stty -a execution.
      * @return value of the given property.
      */
-    protected static int getProperty(String name, String stty) {
+    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);
@@ -134,11 +228,16 @@
                 pattern = Pattern.compile("(\\S*)\\s+" + name);
                 matcher = pattern.matcher(stty);
                 if (!matcher.find()) {
-                    return -1;
+                    return null;
                 }
             }
         }
-        return parseControlChar(matcher.group(1));
+        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) {
@@ -176,25 +275,53 @@
         }
     }
 
-    private String stty(final String args) throws IOException, InterruptedException {
-        checkNotNull(args);
-        return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
-    }
-
-    private String exec(final String cmd) throws IOException, InterruptedException {
-        checkNotNull(cmd);
-        return exec(shCommand, "-c", cmd);
+    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);
 
-        ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
         Log.trace("Running: ", cmd);
 
-        Process p = Runtime.getRuntime().exec(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;
@@ -215,20 +342,17 @@
             close(in, out, err);
         }
 
-        String result = bout.toString();
-
-        Log.trace("Result: ", result);
-
-        return result;
+        return bout.toString();
     }
 
     private static void close(final Closeable... closeables) {
         for (Closeable c : closeables) {
-            try {
-                c.close();
-            }
-            catch (Exception e) {
-                // Ignore
+            if (c != null) {
+                try {
+                    c.close();
+                } catch (Exception e) {
+                    // Ignore
+                }
             }
         }
     }
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java	Fri Jun 01 13:04:30 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2012, the original author or authors.
+ * Copyright (c) 2002-2016, the original author or authors.
  *
  * This software is distributable under the BSD license. See the terms of the
  * BSD license in the documentation provided with this software.
--- a/src/jdk.internal.le/share/legal/jline.md	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/share/legal/jline.md	Fri Jun 01 13:04:30 2018 +0200
@@ -1,11 +1,13 @@
-## JLine v2.12.1
+## JLine v2.14.6
 
 ### JLine License
 <pre>
 
-Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>
+Copyright (c) 2002-2016, the original author or authors.
 All rights reserved.
 
+http://www.opensource.org/licenses/bsd-license.php
+
 Redistribution and use in source and binary forms, with or
 without modification, are permitted provided that the following
 conditions are met:
--- a/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Fri Jun 01 13:04:30 2018 +0200
@@ -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
@@ -34,6 +34,8 @@
 
 static jclass recordClass;
 static jmethodID recordConstructor;
+static jclass bufferStateClass;
+static jmethodID bufferStateConstructor;
 
 JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_initIDs
   (JNIEnv *env, jclass) {
@@ -43,6 +45,12 @@
     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
@@ -81,8 +89,6 @@
             return NULL;
         }
         if (record.EventType == KEY_EVENT) {
-            jclass clazz = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
-            jmethodID constr = env->GetMethodID(clazz, "<init>", "(ZCIII)V");
             return env->NewObject(recordClass,
                                   recordConstructor,
                                   record.Event.KeyEvent.bKeyDown,
@@ -125,3 +131,31 @@
     }
     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	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Fri Jun 01 13:04:30 2018 +0200
@@ -173,7 +173,7 @@
             }
         }
         repl.prefs.flush();
-        in.shutdown();
+        in.close();
         try {
             in.getTerminal().restore();
         } catch (Exception ex) {
@@ -1179,7 +1179,7 @@
 
         public TestTerminal(StopDetectingInputStream input) throws Exception {
             super(true);
-            setAnsiSupported(Boolean.getBoolean("test.terminal.ansi.supported"));
+            setAnsiSupported(true);
             setEchoEnabled(false);
             this.input = input;
             int h = DEFAULT_HEIGHT;
@@ -1218,7 +1218,7 @@
         private final CompletionState completionState;
 
         public CheckCompletionKeyMap(KeyMap del, CompletionState completionState) {
-            super(del.getName(), del.isViKeyMap());
+            super(del.getName());
             this.del = del;
             this.completionState = completionState;
         }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Fri Jun 01 13:04:30 2018 +0200
@@ -40,6 +40,7 @@
 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;
@@ -53,13 +54,14 @@
             final NashornCompleter completer, final Function<String, String> docHelper) throws IOException {
         this.historyFile = historyFile;
 
-        TerminalFactory.registerFlavor(Flavor.WINDOWS, isCygwin()? JJSUnixTerminal::new : JJSWindowsTerminal::new);
-        TerminalFactory.registerFlavor(Flavor.UNIX, JJSUnixTerminal::new);
+        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) {
--- a/test/jdk/jdk/internal/jline/console/StripAnsiTest.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/test/jdk/jdk/internal/jline/console/StripAnsiTest.java	Fri Jun 01 13:04:30 2018 +0200
@@ -24,16 +24,11 @@
 /**
  * @test
  * @bug 8080679 8131913
- * @modules jdk.internal.le/jdk.internal.jline
- *          jdk.internal.le/jdk.internal.jline.console:+open
+ * @modules jdk.internal.le/jdk.internal.jline.internal
  * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
  */
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.Method;
-import jdk.internal.jline.UnsupportedTerminal;
-import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.internal.Ansi;
 
 public class StripAnsiTest {
     public static void main(String... args) throws Exception {
@@ -41,16 +36,10 @@
     }
 
     void run() throws Exception {
-        ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ConsoleReader reader = new ConsoleReader(in, out, new UnsupportedTerminal());
-
         String withAnsi = "0\033[s1\033[2J2\033[37;4m3";
         String expected = "0123";
 
-        Method stripAnsi = ConsoleReader.class.getDeclaredMethod("stripAnsi", String.class);
-        stripAnsi.setAccessible(true);
-        String actual = (String) stripAnsi.invoke(reader, withAnsi);
+        String actual = Ansi.stripAnsi(withAnsi);
 
         if (!expected.equals(actual)) {
             throw new IllegalStateException("Did not correctly strip escape sequences: " + actual);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/internal/jline/extra/AnsiInterpretingOutputStreamTest.java	Fri Jun 01 13:04:30 2018 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java	Fri Jun 01 13:04:30 2018 +0200
@@ -49,7 +49,6 @@
 public class PasteAndMeasurementsUITest extends UITesting {
 
     public void testPrevNextSnippet() throws Exception {
-        System.setProperty(ANSI_SUPPORTED_PROPERTY, "true");
         Field cons = System.class.getDeclaredField("cons");
         cons.setAccessible(true);
         Constructor console = Console.class.getDeclaredConstructor();
@@ -69,6 +68,5 @@
                             PROMPT + "\u001b\\[6n");
         });
     }
-        private static final String ANSI_SUPPORTED_PROPERTY = "test.terminal.ansi.supported";
         private static final String LOC = "\033[12;1R";
 }
--- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java	Fri Jun 01 13:04:30 2018 +0200
@@ -83,7 +83,7 @@
                             resource("jshell.console.see.documentation") +
                             REDRAW_PROMPT + "new JShellTest");
             inputSink.write(TAB);
-            waitOutput(out, "jshelltest.JShellTest\n" +
+            waitOutput(out, "\\u001B\\[1mjshelltest.JShellTest\\u001B\\[0m\n" +
                             "JShellTest 0" +
                             REDRAW_PROMPT + "new JShellTest");
             inputSink.write(TAB);
@@ -105,7 +105,7 @@
                             resource("jshell.console.see.documentation") +
                             REDRAW_PROMPT + "new JShellTest\\(");
             inputSink.write(TAB);
-            waitOutput(out, "JShellTest\\(String str\\)\n" +
+            waitOutput(out, "\\u001B\\[1mJShellTest\\(String str\\)\\u001B\\[0m\n" +
                             "JShellTest 1\n" +
                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
@@ -117,7 +117,7 @@
                             resource("jshell.console.see.next.javadoc") +
                             REDRAW_PROMPT + "new JShellTest\\(");
             inputSink.write(TAB);
-            waitOutput(out, "JShellTest\\(String str, int i\\)\n" +
+            waitOutput(out, "\\u001B\\[1mJShellTest\\(String str, int i\\)\\u001B\\[0m\n" +
                             "JShellTest 2\n" +
                             "\n" +
                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
@@ -140,7 +140,7 @@
                             resource("jshell.console.see.documentation") +
                             REDRAW_PROMPT + "new JShellTest\\(");
             inputSink.write(TAB);
-            waitOutput(out, "JShellTest\\(String str\\)\n" +
+            waitOutput(out, "\\u001B\\[1mJShellTest\\(String str\\)\\u001B\\[0m\n" +
                             "JShellTest 1\n" +
                             "1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n" +
                             "\n" +
@@ -152,7 +152,7 @@
                             resource("jshell.console.see.next.javadoc") +
                             REDRAW_PROMPT + "new JShellTest\\(");
             inputSink.write(TAB);
-            waitOutput(out, "JShellTest\\(String str, int i\\)\n" +
+            waitOutput(out, "\\u001B\\[1mJShellTest\\(String str, int i\\)\\u001B\\[0m\n" +
                             "JShellTest 2\n" +
                             "\n" +
                             getMessage("jshell.console.completion.all.completions.number", "[0-9]+") +
--- a/test/langtools/jdk/jshell/UITesting.java	Fri Jun 01 11:34:13 2018 +0200
+++ b/test/langtools/jdk/jshell/UITesting.java	Fri Jun 01 13:04:30 2018 +0200
@@ -192,7 +192,7 @@
     }
 
     protected String clearOut(String what) {
-        return backspace(what.length()) + space(what.length()) + backspace(what.length());
+        return backspace(what.length()) + "\\u001B\\[K";
     }
 
     protected String backspace(int n) {
@@ -222,7 +222,7 @@
     }
 
     protected String resource(String key) {
-        return Pattern.quote(getResource(key).replaceAll("\t", "    "));
+        return Pattern.quote(getResource(key));
     }
 
     protected String getMessage(String key, Object... args) {