
scala.tools.jline.UnixTerminal Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*/
package scala.tools.jline;
import scala.tools.jline.console.Key;
import scala.tools.jline.internal.Configuration;
import scala.tools.jline.internal.Log;
import scala.tools.jline.internal.ReplayPrefixOneCharInputStream;
import scala.tools.jline.internal.TerminalLineSettings;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import static scala.tools.jline.UnixTerminal.UnixKey.*;
import static scala.tools.jline.console.Key.*;
/**
* Terminal that is used for unix platforms. Terminal initialization
* is handled by issuing the stty command against the
* /dev/tty file to disable character echoing and enable
* character input. All known unix systems (including
* Linux and Macintosh OS X) support the stty), so this
* implementation should work for an reasonable POSIX system.
*
* @author Marc Prud'hommeaux
* @author Dale Kemp
* @author Jason Dillon
* @author Jean-Baptiste Onofré
* @since 2.0
*/
public class UnixTerminal
extends TerminalSupport
{
private final TerminalLineSettings settings = new TerminalLineSettings();
private final ReplayPrefixOneCharInputStream replayStream;
private final InputStreamReader replayReader;
public UnixTerminal() throws Exception {
super(true);
this.replayStream = new ReplayPrefixOneCharInputStream(Configuration.getInputEncoding());
this.replayReader = new InputStreamReader(replayStream, replayStream.getEncoding());
}
protected TerminalLineSettings getSettings() {
return settings;
}
/**
* Remove line-buffered input by invoking "stty -icanon min 1"
* against the current terminal.
*/
@Override
public void init() throws Exception {
super.init();
setAnsiSupported(true);
// set the console to be character-buffered instead of line-buffered
settings.set("-icanon min 1");
setEchoEnabled(false);
}
/**
* Restore the original terminal configuration, which can be used when
* shutting down the console reader. The ConsoleReader cannot be
* used after calling this method.
*/
@Override
public void restore() throws Exception {
settings.restore();
super.restore();
// print a newline after the terminal exits.
// this should probably be a configurable.
System.out.println();
}
/**
* Returns the value of stty columns param.
*/
@Override
public int getWidth() {
int w = settings.getProperty("columns");
return w < 1 ? DEFAULT_WIDTH : w;
}
/**
* Returns the value of stty rows>/tt> param.
*/
@Override
public int getHeight() {
int h = settings.getProperty("rows");
return h < 1 ? DEFAULT_HEIGHT : h;
}
@Override
public synchronized void setEchoEnabled(final boolean enabled) {
try {
if (enabled) {
settings.set("echo");
}
else {
settings.set("-echo");
}
super.setEchoEnabled(enabled);
}
catch (Exception e) {
Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo: ", e);
}
}
@Override
public int readVirtualKey(final InputStream in) throws IOException {
int c = readCharacter(in);
if (Key.valueOf(c) == DELETE && settings.getProperty("erase") == DELETE.code) {
c = BACKSPACE.code;
}
UnixKey key = UnixKey.valueOf(c);
// in Unix terminals, arrow keys are represented by a sequence of 3 characters. E.g., the up arrow key yields 27, 91, 68
if (key == ARROW_START) {
// also the escape key is 27 thats why we read until we have something different than 27
// this is a bugfix, because otherwise pressing escape and than an arrow key was an undefined state
while (key == ARROW_START) {
c = readCharacter(in);
key = UnixKey.valueOf(c);
}
if (key == ARROW_PREFIX || key == O_PREFIX) {
c = readCharacter(in);
key = UnixKey.valueOf(c);
if (key == ARROW_UP) {
return CTRL_P.code;
}
else if (key == ARROW_DOWN) {
return CTRL_N.code;
}
else if (key == ARROW_LEFT) {
return CTRL_B.code;
}
else if (key == ARROW_RIGHT) {
return CTRL_F.code;
}
else if (key == HOME_CODE) {
return CTRL_A.code;
}
else if (key == END_CODE) {
return CTRL_E.code;
}
else if (key == DEL_THIRD) {
readCharacter(in); // read 4th & ignore
return DELETE.code;
}
}
else if (c == 'b') { // alt-b: go back a word
return CTRL_O.code; // PREV_WORD
}
else if (c == 'f') { // alt-f: go forward a word
return CTRL_T.code; // NEXT_WORD
}
else if (key == DEL) { // alt-backspace: delete previous word
return CTRL_W.code; // DELETE_PREV_WORD
}
else if (c == 'd') { // alt-d: delete next word
return CTRL_X.code; // DELETE_NEXT_WORD
}
}
// handle unicode characters, thanks for a patch from [email protected]
if (c > 128) {
// handle unicode characters longer than 2 bytes,
// thanks to [email protected]
replayStream.setInput(c, in);
// replayReader = new InputStreamReader(replayStream, encoding);
c = replayReader.read();
}
return c;
}
/**
* Unix keys.
*/
public static enum UnixKey
{
ARROW_START(27),
ARROW_PREFIX(91),
ARROW_LEFT(68),
ARROW_RIGHT(67),
ARROW_UP(65),
ARROW_DOWN(66),
O_PREFIX(79),
HOME_CODE(72),
END_CODE(70),
DEL_THIRD(51),
DEL_SECOND(126),
DEL(127);
public final short code;
UnixKey(final int code) {
this.code = (short) code;
}
private static final Map codes;
static {
Map map = new HashMap();
for (UnixKey key : UnixKey.values()) {
map.put(key.code, key);
}
codes = map;
}
public static UnixKey valueOf(final int code) {
return codes.get((short) code);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy