package com.jediterm.terminal.emulator;
import com.google.common.base.Ascii;
import com.jediterm.terminal.CharacterUtils;
import com.jediterm.terminal.DataStreamIteratingEmulator;
import com.jediterm.terminal.Terminal;
import com.jediterm.terminal.TerminalColor;
import com.jediterm.terminal.TerminalDataStream;
import com.jediterm.terminal.TerminalMode;
import com.jediterm.terminal.TerminalOutputStream;
import com.jediterm.terminal.TextStyle;
import com.jediterm.terminal.emulator.mouse.MouseFormat;
import com.jediterm.terminal.emulator.mouse.MouseMode;
import org.apache.log4j.Logger;
import java.io.IOException;
/**
* The main terminal emulator class.
* <p/>
* Obtains data from the {@link com.jediterm.terminal.TerminalDataStream}, interprets terminal ANSI escape sequences as commands and directs them
* as well as plain data characters to the {@link com.jediterm.terminal.Terminal}
*
* @author traff
*/
public class JediEmulator extends DataStreamIteratingEmulator {
private static final Logger LOG = Logger.getLogger(JediEmulator.class);
private static int logThrottlerCounter = 0;
private static int logThrottlerRatio = 100;
private static int logThrottlerLimit = logThrottlerRatio;
private final TerminalOutputStream myOutputStream;
public JediEmulator(TerminalDataStream dataStream, TerminalOutputStream outputStream, Terminal terminal) {
super(dataStream, terminal);
myOutputStream = outputStream;
}
@Override
public void processChar(char ch, Terminal terminal) throws IOException {
switch (ch) {
case 0:
break;
case Ascii.BEL: //Bell (Ctrl-G)
terminal.beep();
break;
case Ascii.BS: //Backspace (Ctrl-H)
terminal.backspace();
break;
case Ascii.CR: //Carriage return (Ctrl-M)
terminal.carriageReturn();
break;
case Ascii.ENQ: //Return terminal status (Ctrl-E). Default response is an empty string
unsupported("Terminal status:" + escapeSequenceToString(ch));
break;
case Ascii.FF: //Form Feed or New Page (NP). Ctrl-L treated the same as LF
case Ascii.LF: //Line Feed or New Line (NL). (LF is Ctrl-J)
case Ascii.VT: //Vertical Tab (Ctrl-K). This is treated the same as LF.
// '\n'
terminal.newLine();
break;
case Ascii.SI: //Shift In (Ctrl-O) -> Switch to Standard Character Set. This invokes the G0 character set (the default)
//LS0 (locking shift 0)
//Map G0 into GL
terminal.mapCharsetToGL(0);
break;
case Ascii.SO: //Shift Out (Ctrl-N) -> Switch to Alternate Character Set. This invokes the G1 character set (the default)
//LS1 (locking shift 1)
//Map G1 into GL
terminal.mapCharsetToGL(1);
break;
case Ascii.HT: // Horizontal Tab (HT) (Ctrl-I)
terminal.horizontalTab();
break;
case Ascii.ESC: // ESC
processEscapeSequence(myDataStream.getChar(), myTerminal);
break;
default:
if (ch <= Ascii.US) {
StringBuilder sb = new StringBuilder("Unhandled control character:");
CharacterUtils.appendChar(sb, CharacterUtils.CharacterType.NONE, ch);
unhandledLogThrottler(sb.toString());
}
else { // Plain characters
myDataStream.pushChar(ch);
String nonControlCharacters = myDataStream.readNonControlCharacters(terminal.distanceToLineEnd());
terminal.writeCharacters(nonControlCharacters);
}
break;
}
}
private void processEscapeSequence(char ch, Terminal terminal) throws IOException {
switch (ch) {
case '[': // Control Sequence Introducer (CSI)
final ControlSequence args = new ControlSequence(myDataStream);
if (LOG.isDebugEnabled()) {
LOG.debug(args.appendTo("Control sequence\nparsed :"));
}
if (!args.pushBackReordered(myDataStream)) {
boolean result = processControlSequence(args);
if (!result) {
StringBuilder sb = new StringBuilder();
sb.append("Unhandled Control sequence\n");
sb.append("parsed :");
args.appendToBuffer(sb);
sb.append('\n');
sb.append("bytes read :ESC[");
LOG.error(sb.toString());
}
}
break;
case 'D': //Index (IND)
terminal.index();
break;
case 'E': //Next Line (NEL)
terminal.nextLine();
break;
case 'H': //Horizontal Tab Set (HTS)
terminal.setTabStopAtCursor();
break;
case 'M': // Reverse Index (RI)
terminal.reverseIndex();
break;
case 'N':
terminal.singleShiftSelect(2); //Single Shift Select of G2 Character Set (SS2). This affects next character only.
break;
case 'O':
terminal.singleShiftSelect(3); //Single Shift Select of G3 Character Set (SS3). This affects next character only.
break;
case ']': // Operating System Command (OSC)
// xterm uses it to set parameters like windows title
final SystemCommandSequence command = new SystemCommandSequence(myDataStream);
if (!operatingSystemCommand(command)) {
LOG.error("Error processing OSC " + command.getSequenceString());
}
break;
case '6':
unsupported("Back Index (DECBI), VT420 and up");
break;
case '7': //Save Cursor (DECSC)
terminal.saveCursor();
break;
case '8':
terminal.restoreCursor();
break;
case '9':
unsupported("Forward Index (DECFI), VT420 and up");
break;
case '=': //Application Keypad (DECKPAM)
setModeEnabled(TerminalMode.Keypad, true);
break;
case '>': //Normal Keypad (DECKPNM)
setModeEnabled(TerminalMode.Keypad, false);
break;
case 'F': //Cursor to lower left corner of the screen
terminal.cursorPosition(1, terminal.getTerminalHeight());
break;
case 'c': //Full Reset (RIS)
terminal.reset();
break;
case 'n': //Invoke the G2 Character Set as GL - locking shift 2 (LS2)
myTerminal.mapCharsetToGL(2);
break;
case 'o': //Invoke the G3 Character Set as GL - locking shift 3 (LS3)
myTerminal.mapCharsetToGL(3);
break;
case '|': //Invoke the G3 Character Set as GR - locking shift 3, right (LS3R)
myTerminal.mapCharsetToGR(3);
break;
case '}': //Invoke the G2 Character Set as GR - locking shift 2, right (LS2R)
myTerminal.mapCharsetToGR(2);
break;
case '~': //Invoke the G1 Character Set as GR - locking shift 1, right (LS1R)
myTerminal.mapCharsetToGR(1);
break;
case '#':
case '(':
case ')':
case '*':
case '+':
case '$':
case '@':
case '%':
case '.':
case '/':
case ' ':
processTwoCharSequence(ch, terminal);
break;
default:
unsupported(ch);
}
}
private boolean operatingSystemCommand(SystemCommandSequence args) {
Integer i = args.getIntAt(0);
if (i != null) {
switch (i) {
case 0: //Icon name/title
case 2: //Title
String name = args.getStringAt(1);
if (name != null) {
myTerminal.setWindowTitle(name);
return true;
}
}
}
return false;
}
private void processTwoCharSequence(char ch, Terminal terminal) throws IOException {
char secondCh = myDataStream.getChar();
switch (ch) {
case ' ':
switch (secondCh) {
//About different character sets: http://en.wikipedia.org/wiki/ISO/IEC_2022
case 'F': //7-bit controls
unsupported("Switching ot 7-bit");
break;
case 'G': //8-bit controls
unsupported("Switching ot 8-bit");
break;
//About ANSI conformance levels: http://www.vt100.net/docs/vt510-rm/ANSI
case 'L': //Set ANSI conformance level 1 and 2
case 'M':
terminal.setAnsiConformanceLevel(1);
break;
case 'N': //Set ANSI conformance level 3
terminal.setAnsiConformanceLevel(3);
break;
default:
unsupported(ch, secondCh);
}
break;
case '#':
switch (secondCh) {
case '8':
terminal.fillScreen('E');
break;
default:
unsupported(ch, secondCh);
}
break;
case '%':
switch (secondCh) {
case '@': // Select default character set. That is ISO 8859-1
case 'G': // Select UTF-8 character set
unsupported("Selecting charset is unsupported: " + escapeSequenceToString(ch, secondCh));
break;
default:
unsupported(ch, secondCh);
}
break;
case '(':
terminal.designateCharacterSet(0, secondCh); //Designate G0 Character set (VT100)
break;
case ')':
terminal.designateCharacterSet(1, secondCh); //Designate G1 Character set (VT100)
break;
case '*':
terminal.designateCharacterSet(2, secondCh); //Designate G2 Character set (VT220)
break;
case '+':
terminal.designateCharacterSet(3, secondCh); //Designate G3 Character set (VT220)
break;
case '-':
terminal.designateCharacterSet(1, secondCh); //Designate G1 Character set (VT300)
break;
case '.':
terminal.designateCharacterSet(2, secondCh); //Designate G2 Character set (VT300)
break;
case '/':
terminal.designateCharacterSet(3, secondCh); //Designate G3 Character set (VT300)
break;
case '$':
case '@':
unsupported(ch, secondCh);
}
}
/**
* This method is used to handle unknown sequences. Can be overriden.
*
* @param sequenceChars are the characters of the unhandled sequence following the ESC character
* (first ESC is excluded from the sequenceChars)
*/
protected void unsupported(char... sequenceChars) {
unsupported(escapeSequenceToString(sequenceChars));
}
/**
* This method is used to report about know unsupported sequences
* @param msg The message describing the sequence
*/
private static void unsupported(String msg) {
unhandledLogThrottler("Unsupported control characters: " + msg);
}
private static void unhandledLogThrottler(String msg) {
logThrottlerCounter++;
if (logThrottlerCounter < logThrottlerLimit) {
if (logThrottlerCounter % (logThrottlerLimit / logThrottlerRatio) == 0) {
if (logThrottlerLimit / logThrottlerRatio > 1 ) {
msg += " and "+ ( logThrottlerLimit / logThrottlerRatio ) + " more...";
}
LOG.error(msg);
}
} else {
logThrottlerLimit *= 10;
}
}
private static String escapeSequenceToString(final char... b) {
StringBuilder sb = new StringBuilder("ESC ");
for (char c : b) {
sb.append(' ');
sb.append(c);
}
return sb.toString();
}
private boolean processControlSequence(ControlSequence args) {
switch (args.getFinalChar()) {
case '@':
return insertBlankCharacters(args); //ICH
case 'A':
return cursorUp(args); //CUU
case 'B':
return cursorDown(args); //CUD
case 'C':
return cursorForward(args); //CUF
case 'D':
return cursorBackward(args); //CUB
case 'E':
return cursorNextLine(args); //CNL
case 'F':
return cursorPrecedingLine(args); //CPL
case 'G':
case '`':
return cursorHorizontalAbsolute(args); //CHA
case 'f':
case 'H': //CUP
return cursorPosition(args);
case 'J': //DECSED
return eraseInDisplay(args);
case 'K': //EL
return eraseInLine(args);
case 'L': //IL
return insertLines(args);
case 'M': //DL
return deleteLines(args);
case 'X': //ECH
return eraseCharacters(args);
case 'P': //DCH
return deleteCharacters(args);
case 'S': //SU
return scrollUp(args);
case 'T': //SD
return scrollDown(args);
case 'c': //Send Device Attributes (Primary DA)
if (args.startsWithMoreMark()) { //Send Device Attributes (Secondary DA)
if (args.getArg(0, 0) == 0) { //apply on to VT220 but xterm extends this to VT100
sendDeviceAttributes();
return true;
}
return false;
}
return sendDeviceAttributes();
case 'd': //VPA
return linePositionAbsolute(args);
case 'g': // Tab Clear (TBC)
return tabClear(args.getArg(0, 0));
case 'h': //Set Mode (SM) or DEC Private Mode Set (DECSET)
return setModeOrPrivateMode(args, true);
case 'l': //Reset Mode (RM) or DEC Private Mode Reset (DECRST)
return setModeOrPrivateMode(args, false);
case 'm':
if (args.startsWithMoreMark()) { //Set or reset resource-values used by xterm
// to decide whether to construct escape sequences holding information about
// the modifiers pressed with a given key
return false;
}
return characterAttributes(args); //Character Attributes (SGR)
case 'n':
return deviceStatusReport(args); //DSR
case 'r':
if (args.startsWithQuestionMark()) {
return restoreDecPrivateModeValues(args); //
}
else {
//Set Top and Bottom Margins
return setScrollingRegion(args); //DECSTBM
}
default:
return false;
}
}
private boolean tabClear(int mode) {
if (mode == 0) { //Clear Current Column (default)
myTerminal.clearTabStopAtCursor();
return true;
}
else if (mode == 3) {
myTerminal.clearAllTabStops();
return true;
}
else {
return false;
}
}
private boolean eraseCharacters(ControlSequence args) {
myTerminal.eraseCharacters(args.getArg(0, 1));
return true;
}
private boolean setModeOrPrivateMode(ControlSequence args, boolean enabled) {
if (args.startsWithQuestionMark()) { // DEC Private Mode
switch (args.getArg(0, -1)) {
case 1: //Cursor Keys Mode (DECCKM)
setModeEnabled(TerminalMode.CursorKey, enabled);
return true;
case 3: //132 Column Mode (DECCOLM)
setModeEnabled(TerminalMode.WideColumn, enabled);
return true;
case 4: //Smooth (Slow) Scroll (DECSCLM)
setModeEnabled(TerminalMode.SmoothScroll, enabled);
return true;
case 5: //Reverse Video (DECSCNM)
setModeEnabled(TerminalMode.ReverseVideo, enabled);
return true;
case 6: //Origin Mode (DECOM)
setModeEnabled(TerminalMode.OriginMode, enabled);
return true;
case 7: //Wraparound Mode (DECAWM)
setModeEnabled(TerminalMode.AutoWrap, enabled);
return true;
case 8: //Auto-repeat Keys (DECARM)
setModeEnabled(TerminalMode.AutoRepeatKeys, enabled);
return true;
case 12: //Start Blinking Cursor (att610)
//setModeEnabled(TerminalMode.CursorBlinking, enabled);
//We want to show blinking cursor always
return true;
case 25:
setModeEnabled(TerminalMode.CursorVisible, enabled);
return true;
case 40: //Allow 80->132 Mode
setModeEnabled(TerminalMode.AllowWideColumn, enabled);
return true;
case 45: //Reverse-wraparound Mode
setModeEnabled(TerminalMode.ReverseWrapAround, enabled);
return true;
case 47:
case 1047:
setModeEnabled(TerminalMode.AlternateBuffer, enabled);
return true;
case 1048:
setModeEnabled(TerminalMode.StoreCursor, enabled);
return true;
case 1049: //Save cursor and use Alternate Screen Buffer
setModeEnabled(TerminalMode.StoreCursor, enabled);
setModeEnabled(TerminalMode.AlternateBuffer, enabled);
return true;
case 1000:
if (enabled) {
setMouseMode(MouseMode.MOUSE_REPORTING_NORMAL);
}
else {
setMouseMode(MouseMode.MOUSE_REPORTING_NONE);
}
return true;
case 1001:
if (enabled) {
setMouseMode(MouseMode.MOUSE_REPORTING_HILITE);
}
else {
setMouseMode(MouseMode.MOUSE_REPORTING_NONE);
}
return true;
case 1002:
if (enabled) {
setMouseMode(MouseMode.MOUSE_REPORTING_BUTTON_MOTION);
}
else {
setMouseMode(MouseMode.MOUSE_REPORTING_NONE);
}
return true;
case 1003:
if (enabled) {
setMouseMode(MouseMode.MOUSE_REPORTING_ALL_MOTION);
}
else {
setMouseMode(MouseMode.MOUSE_REPORTING_NONE);
}
return true;
case 1005:
if (enabled) {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_XTERM_EXT);
}
else {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_XTERM);
}
return true;
case 1006:
if (enabled) {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_SGR);
}
else {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_XTERM);
}
return true;
case 1015:
if (enabled) {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_URXVT);
}
else {
myTerminal.setMouseFormat(MouseFormat.MOUSE_FORMAT_XTERM);
}
return true;
default:
return false;
}
}
else {
switch (args.getArg(0, -1)) {
case 2: //Keyboard Action Mode (AM)
setModeEnabled(TerminalMode.KeyboardAction, enabled);
return true;
case 4: //Insert Mode (IRM)
setModeEnabled(TerminalMode.InsertMode, enabled);
return true;
case 12: //Send/receive (SRM)
setModeEnabled(TerminalMode.SendReceive, enabled);
return true;
case 20:
setModeEnabled(TerminalMode.AutoNewLine, enabled);
return true;
default:
return false;
}
}
}
private boolean linePositionAbsolute(ControlSequence args) {
int y = args.getArg(0, 1);
myTerminal.linePositionAbsolute(y);
return true;
}
private boolean restoreDecPrivateModeValues(ControlSequence args) {
LOG.error("Unsupported: " + args.toString());
return false;
}
private boolean deviceStatusReport(ControlSequence args) {
if (args.startsWithQuestionMark()) {
LOG.error("Don't support DEC-specific Device Report Status");
return false;
}
int c = args.getArg(0, 0);
if (c == 5) {
String str = "\033[0n";
LOG.debug("Sending Device Report Status : " + str);
myOutputStream.sendString(str);
return true;
}
else if (c == 6) {
int row = myTerminal.getCursorY();
int column = myTerminal.getCursorX();
String str = "\033[" + row + ";" + column + "R";
LOG.debug("Sending Device Report Status : " + str);
myOutputStream.sendString(str);
return true;
}
else {
LOG.error("Sending Device Report Status : unsupported parameter: " + args.toString());
return false;
}
}
private boolean insertLines(ControlSequence args) {
myTerminal.insertLines(args.getArg(0, 1));
return true;
}
private boolean sendDeviceAttributes() {
if (LOG.isDebugEnabled()) {
LOG.debug("Identifying to remote system as VT102");
}
myOutputStream.sendBytes(CharacterUtils.VT102_RESPONSE);
return true;
}
private boolean cursorHorizontalAbsolute(ControlSequence args) {
int x = args.getArg(0, 1);
myTerminal.cursorHorizontalAbsolute(x);
return true;
}
private boolean cursorNextLine(ControlSequence args) {
int dx = args.getArg(0, 1);
dx = dx == 0 ? 1 : dx;
myTerminal.cursorDown(dx);
myTerminal.cursorHorizontalAbsolute(1);
return true;
}
private boolean cursorPrecedingLine(ControlSequence args) {
int dx = args.getArg(0, 1);
dx = dx == 0 ? 1 : dx;
myTerminal.cursorUp(dx);
myTerminal.cursorHorizontalAbsolute(1);
return true;
}
private boolean insertBlankCharacters(ControlSequence args) {
final int count = args.getArg(0, 1);
myTerminal.insertBlankCharacters(count);
return true;
}
private boolean eraseInDisplay(ControlSequence args) {
// ESC [ Ps J
final int arg = args.getArg(0, 0);
if (args.startsWithQuestionMark()) {
//TODO: support ESC [ ? Ps J - Selective Erase (DECSED)
return false;
}
myTerminal.eraseInDisplay(arg);
return true;
}
private boolean eraseInLine(ControlSequence args) {
// ESC [ Ps K
final int arg = args.getArg(0, 0);
if (args.startsWithQuestionMark()) {
//TODO: support ESC [ ? Ps K - Selective Erase (DECSEL)
return false;
}
myTerminal.eraseInLine(arg);
return true;
}
private boolean deleteLines(ControlSequence args) {
// ESC [ Ps M
myTerminal.deleteLines(args.getArg(0, 1));
return true;
}
private boolean deleteCharacters(ControlSequence args) {
// ESC [ Ps P
final int arg = args.getArg(0, 1);
myTerminal.deleteCharacters(arg);
return true;
}
private boolean cursorBackward(ControlSequence args) {
int dx = args.getArg(0, 1);
dx = dx == 0 ? 1 : dx;
myTerminal.cursorBackward(dx);
return true;
}
private boolean setScrollingRegion(ControlSequence args) {
final int top = args.getArg(0, 1);
final int bottom = args.getArg(1, myTerminal.getTerminalHeight());
myTerminal.setScrollingRegion(top, bottom);
return true;
}
private boolean scrollUp(ControlSequence args) {
int count = args.getArg(0, 1);
myTerminal.scrollUp(count);
return true;
}
private boolean scrollDown(ControlSequence args) {
int count = args.getArg(0, 1);
myTerminal.scrollDown(count);
return true;
}
private boolean cursorForward(ControlSequence args) {
int countX = args.getArg(0, 1);
countX = countX == 0 ? 1 : countX;
myTerminal.cursorForward(countX);
return true;
}
private boolean cursorDown(ControlSequence cs) {
int countY = cs.getArg(0, 0);
countY = countY == 0 ? 1 : countY;
myTerminal.cursorDown(countY);
return true;
}
private boolean cursorPosition(ControlSequence cs) {
final int argy = cs.getArg(0, 1);
final int argx = cs.getArg(1, 1);
myTerminal.cursorPosition(argx, argy);
return true;
}
private boolean characterAttributes(final ControlSequence args) {
TextStyle styleState = createStyleState(myTerminal.getStyleState().getCurrent().clone(), args);
myTerminal.characterAttributes(styleState);
return true;
}
private static TextStyle createStyleState(TextStyle textStyle, ControlSequence args) {
final int argCount = args.getCount();
if (argCount == 0) {
textStyle = new TextStyle();
}
int i = 0;
while (i < argCount) {
int step = 1;
final int arg = args.getArg(i, -1);
if (arg == -1) {
LOG.error("Error in processing char attributes, arg " + i);
i++;
continue;
}
switch (arg) {
case 0: //Normal (default)
textStyle = new TextStyle();
break;
case 1:// Bold
textStyle.setOption(TextStyle.Option.BOLD, true);
break;
case 2:// Dim
textStyle.setOption(TextStyle.Option.DIM, true);
break;
case 3:// Italic
textStyle.setOption(TextStyle.Option.ITALIC, true);
break;
case 4:// Underlined
textStyle.setOption(TextStyle.Option.UNDERLINED, true);
break;
case 5:// Blink (appears as Bold)
textStyle.setOption(TextStyle.Option.BLINK, true);
break;
case 7:// Inverse
textStyle.setOption(TextStyle.Option.INVERSE, true);
break;
case 8: // Invisible (hidden)
textStyle.setOption(TextStyle.Option.HIDDEN, true);
break;
case 22: //Normal (neither bold nor faint)
textStyle.setOption(TextStyle.Option.BOLD, false);
textStyle.setOption(TextStyle.Option.DIM, false);
break;
case 23: // Not italic
textStyle.setOption(TextStyle.Option.ITALIC, false);
break;
case 24: // Not underlined
textStyle.setOption(TextStyle.Option.UNDERLINED, false);
break;
case 25: //Steady (not blinking)
textStyle.setOption(TextStyle.Option.BLINK, false);
break;
case 27: //Positive (not inverse)
textStyle.setOption(TextStyle.Option.INVERSE, false);
break;
case 28: //Visible, i.e. not hidden
textStyle.setOption(TextStyle.Option.HIDDEN, false);
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
textStyle.setForeground(TerminalColor.index(arg - 30));
break;
case 38: // Set xterm-256 text color
TerminalColor color256 = getColor256(args, i);
if (color256 != null) {
textStyle.setForeground(color256);
step = getColor256Step(args, i);
}
break;
case 39: // Default (original) foreground
textStyle.setForeground(null);
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
textStyle.setBackground(TerminalColor.index(arg - 40));
break;
case 48: // Set xterm-256 background color
TerminalColor bgColor256 = getColor256(args, i);
if (bgColor256 != null) {
textStyle.setBackground(bgColor256);
step = getColor256Step(args, i);
}
break;
case 49: //Default (original) foreground
textStyle.setBackground(null);
break;
case 90:
case 91:
case 92:
case 93:
case 94:
case 95:
case 96:
case 97:
//Bright versions of the ISO colors for foreground
textStyle.setForeground(ColorPalette.getIndexedColor(arg - 82));
break;
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
//Bright versions of the ISO colors for background
textStyle.setBackground(ColorPalette.getIndexedColor(arg - 92));
break;
default:
LOG.error("Unknown character attribute:" + arg);
}
i = i + step;
}
return textStyle;
}
private static TerminalColor getColor256(ControlSequence args, int index) {
int code = args.getArg(index + 1, 0);
if (code == 2) {
/* direct color in rgb space */
int val0 = args.getArg(index + 2, -1);
int val1 = args.getArg(index + 3, -1);
int val2 = args.getArg(index + 4, -1);
if ((val0 >= 0 && val0 < 256) &&
(val1 >= 0 && val1 < 256) &&
(val2 >= 0 && val2 < 256)) {
return new TerminalColor(val0, val1, val2);
}
else {
LOG.error("Bogus color setting " + args.toString());
return null;
}
}
else if (code == 5) {
/* indexed color */
return ColorPalette.getIndexedColor(args.getArg(index + 2, 0));
}
else {
LOG.error("Unsupported code for color attribute " + args.toString());
return null;
}
}
private static int getColor256Step(ControlSequence args, int i) {
int code = args.getArg(i + 1, 0);
if (code == 2) {
return 5;
} else if (code == 5) {
return 3;
}
return 1;
}
private boolean cursorUp(ControlSequence cs) {
int arg = cs.getArg(0, 0);
arg = arg == 0 ? 1 : arg;
myTerminal.cursorUp(arg);
return true;
}
private void setModeEnabled(final TerminalMode mode, final boolean enabled) {
if (LOG.isDebugEnabled()) {
LOG.info("Setting mode " + mode + " enabled = " + enabled);
}
myTerminal.setModeEnabled(mode, enabled);
}
public void setMouseMode(MouseMode mouseMode) {
myTerminal.setMouseMode(mouseMode);
}
}