--- /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 synchronized Terminal get() {
+ return get(null);
+ }
+
public static Terminal getFlavor(final Flavor flavor) throws Exception {
- return FLAVORS.getOrDefault(flavor, () -> {throw new InternalError();}).call();
+ return getFlavor(flavor, null);
}
- public static void registerFlavor(final Flavor flavor, final Callable<? extends Terminal> sup) {
- FLAVORS.put(flavor, sup);
+ @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);
+ }
+
+ public UnixTerminal(String ttyDevice) throws Exception {
+ this(ttyDevice, null);
}
- protected TerminalLineSettings getSettings() {
+ 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 (buf.cursor == 0) {
- return;
- }
- else if (mask != null) {
- c = mask;
- }
- else {
- print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
- return;
+ } else if (l0 < l1) {
+ tputs("carriage_return");
+ rawPrint('\n', l1 - l0);
+ c0 = 0;
}
-
- // null character mask: don't output anything
- if (mask == NULL_MASK) {
- 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");
+ }
+ }
}
-
- 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,83 +2188,160 @@
}
// 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);
- }
-
- return getPrintableCharacters(c).length();
+ public int readCharacter(final char... allowed) throws IOException {
+ return readCharacter(false, allowed);
}
- /**
- * Return the number of characters that will be printed when the specified
- * character is echoed to the screen
- *
- * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
- */
- private StringBuilder getPrintableCharacters(final int ch) {
- StringBuilder sbuff = new StringBuilder();
-
- if (ch >= 32) {
- if (ch < 127) {
- sbuff.append(ch);
- }
- else if (ch == 127) {
- sbuff.append('^');
- sbuff.append('?');
- }
- else {
- sbuff.append('M');
- sbuff.append('-');
-
- if (ch >= (128 + 32)) {
- if (ch < (128 + 127)) {
- sbuff.append((char) (ch - 128));
- }
- else {
- sbuff.append('^');
- sbuff.append('?');
- }
- }
- else {
- sbuff.append('^');
- sbuff.append((char) (ch - 128 + 64));
- }
- }
- }
- else {
- sbuff.append('^');
- sbuff.append((char) (ch + 64));
- }
-
- return sbuff;
- }
-
- public final int readCharacter(final char... allowed) throws IOException {
+ 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()) < 0) {
+ while (Arrays.binarySearch(allowed, c = (char) readCharacter(checkForAltKeyCombo)) < 0) {
// nothing
}
return c;
}
+ /**
+ * Read from the input stream and decode an operation from the key map.
+ *
+ * The input stream will be read character by character until a matching
+ * binding can be found. Characters that can't possibly be matched to
+ * any binding will be discarded.
+ *
+ * @param keys the KeyMap to use for decoding the input stream
+ * @return the decoded binding or <code>null</code> if the end of
+ * stream has been reached
+ */
+ public Object readBinding(KeyMap keys) throws IOException {
+ Object o;
+ opBuffer.setLength(0);
+ do {
+ int c = pushBackChar.isEmpty() ? readCharacter() : pushBackChar.pop();
+ if (c == -1) {
+ return null;
+ }
+ opBuffer.appendCodePoint(c);
+
+ if (recording) {
+ macro += new String(Character.toChars(c));
+ }
+
+ if (quotedInsert) {
+ o = Operation.SELF_INSERT;
+ quotedInsert = false;
+ } else {
+ o = keys.getBound(opBuffer);
+ }
+
+ /*
+ * The kill ring keeps record of whether or not the
+ * previous command was a yank or a kill. We reset
+ * that state here if needed.
+ */
+ if (!recording && !(o instanceof KeyMap)) {
+ if (o != Operation.YANK_POP && o != Operation.YANK) {
+ killRing.resetLastYank();
+ }
+ if (o != Operation.KILL_LINE && o != Operation.KILL_WHOLE_LINE
+ && o != Operation.BACKWARD_KILL_WORD && o != Operation.KILL_WORD
+ && o != Operation.UNIX_LINE_DISCARD && o != Operation.UNIX_WORD_RUBOUT) {
+ killRing.resetLastKill();
+ }
+ }
+
+ if (o == Operation.DO_LOWERCASE_VERSION) {
+ opBuffer.setLength(opBuffer.length() - 1);
+ opBuffer.append(Character.toLowerCase((char) c));
+ o = keys.getBound(opBuffer);
+ }
+
+ /*
+ * A KeyMap indicates that the key that was struck has a
+ * number of keys that can follow it as indicated in the
+ * map. This is used primarily for Emacs style ESC-META-x
+ * lookups. Since more keys must follow, go back to waiting
+ * for the next key.
+ */
+ if (o instanceof KeyMap) {
+ /*
+ * The ESC key (#27) is special in that it is ambiguous until
+ * you know what is coming next. The ESC could be a literal
+ * escape, like the user entering vi-move mode, or it could
+ * be part of a terminal control sequence. The following
+ * logic attempts to disambiguate things in the same
+ * fashion as regular vi or readline.
+ *
+ * When ESC is encountered and there is no other pending
+ * character in the pushback queue, then attempt to peek
+ * into the input stream (if the feature is enabled) for
+ * 150ms. If nothing else is coming, then assume it is
+ * not a terminal control sequence, but a raw escape.
+ */
+ if (c == ESCAPE
+ && pushBackChar.isEmpty()
+ && in.isNonBlockingEnabled()
+ && in.peek(escapeTimeout) == READ_EXPIRED) {
+ o = ((KeyMap) o).getAnotherKey();
+ if (o == null || o instanceof KeyMap) {
+ continue;
+ }
+ opBuffer.setLength(0);
+ } else {
+ continue;
+ }
+ }
+
+ /*
+ * If we didn't find a binding for the key and there is
+ * more than one character accumulated then start checking
+ * the largest span of characters from the beginning to
+ * see if there is a binding for them.
+ *
+ * For example if our buffer has ESC,CTRL-M,C the getBound()
+ * called previously indicated that there is no binding for
+ * this sequence, so this then checks ESC,CTRL-M, and failing
+ * that, just ESC. Each keystroke that is pealed off the end
+ * during these tests is stuffed onto the pushback buffer so
+ * they won't be lost.
+ *
+ * If there is no binding found, then we go back to waiting for
+ * input.
+ */
+ while (o == null && opBuffer.length() > 0) {
+ c = opBuffer.charAt(opBuffer.length() - 1);
+ opBuffer.setLength(opBuffer.length() - 1);
+ Object o2 = keys.getBound(opBuffer);
+ if (o2 instanceof KeyMap) {
+ o = ((KeyMap) o2).getAnotherKey();
+ if (o == null) {
+ continue;
+ } else {
+ pushBackChar.push((char) c);
+ }
+ }
+ }
+
+ } while (o == null || o instanceof KeyMap);
+
+ return o;
+ }
+
+ public String getLastBinding() {
+ return opBuffer.toString();
+ }
+
//
// Key Bindings
//
@@ -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,8 +2480,11 @@
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) {