Add colors to the interactive interpreter
This commit is contained in:
parent
058e937c3e
commit
b298e118e3
|
@ -1,7 +1,5 @@
|
|||
package interpreter;
|
||||
|
||||
import sexpression.SExpression;
|
||||
|
||||
public class InteractiveLispInterpreter extends LispInterpreter {
|
||||
|
||||
private static final String PROMPT = "~ ";
|
||||
|
@ -13,9 +11,9 @@ public class InteractiveLispInterpreter extends LispInterpreter {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void printSExpression(SExpression sExpression) {
|
||||
protected void evaluateAndPrintNextSExpression() {
|
||||
environment.getOutput().println();
|
||||
super.printSExpression(sExpression);
|
||||
super.evaluateAndPrintNextSExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,7 +31,7 @@ public class LispInterpreter {
|
|||
|
||||
protected void prompt() {}
|
||||
|
||||
private void evaluateAndPrintNextSExpression() {
|
||||
protected void evaluateAndPrintNextSExpression() {
|
||||
try {
|
||||
evaluateAndPrintNextSExpressionWithException();
|
||||
} catch (LispException e) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.googlecode.lanterna.terminal.*;
|
|||
|
||||
import interpreter.*;
|
||||
import terminal.LispTerminal;
|
||||
import terminal.SafeStream.SafePipedOutputStream;
|
||||
import terminal.SafeStream.SafeOutputStream;
|
||||
import terminal.SafeStream.UncheckedIOException;
|
||||
|
||||
public class LispMain {
|
||||
|
@ -35,7 +35,7 @@ public class LispMain {
|
|||
private PipedInputStream outputReader;
|
||||
private PipedOutputStream outputWriter;
|
||||
private PrintStream outputStream;
|
||||
private SafePipedOutputStream safeOutputWriter;
|
||||
private SafeOutputStream safeOutputWriter;
|
||||
private LispTerminal lispTerminal;
|
||||
|
||||
private void runInteractive() {
|
||||
|
@ -60,7 +60,7 @@ public class LispMain {
|
|||
outputReader = new PipedInputStream();
|
||||
outputWriter = new PipedOutputStream(outputReader);
|
||||
outputStream = new PrintStream(outputWriter);
|
||||
safeOutputWriter = new SafePipedOutputStream(outputWriter);
|
||||
safeOutputWriter = new SafeOutputStream(outputWriter);
|
||||
lispTerminal = new LispTerminal(createIOSafeTerminal(), inputWriter, outputReader);
|
||||
}
|
||||
|
||||
|
@ -82,11 +82,11 @@ public class LispMain {
|
|||
builder.setErrorOutput(outputStream);
|
||||
builder.setTerminationFunction(this::shutdown);
|
||||
builder.setErrorTerminationFunction(this::shutdown);
|
||||
builder.setPromptDecorator(makeSegmentDecorator(ANSI_GREEN));
|
||||
builder.setValueOutputDecorator(s -> s);
|
||||
builder.setWarningOutputDecorator(s -> s);
|
||||
builder.setErrorOutputDecorator(s -> s);
|
||||
builder.setCriticalOutputDecorator(s -> s);
|
||||
builder.setPromptDecorator(s -> s + END_OF_SEGMENT);
|
||||
builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN));
|
||||
builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW));
|
||||
builder.setErrorOutputDecorator(makeColorDecorator(ANSI_RED));
|
||||
builder.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -98,16 +98,6 @@ public class LispMain {
|
|||
safeOutputWriter.close();
|
||||
}
|
||||
|
||||
private static Function<String, String> makeSegmentDecorator(String color) {
|
||||
return new Function<String, String>() {
|
||||
|
||||
@Override
|
||||
public String apply(String s) {
|
||||
return s + END_OF_SEGMENT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void runWithFile(String fileName) {
|
||||
buildFileInterpreter(fileName).interpret();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package terminal;
|
||||
|
||||
import com.googlecode.lanterna.terminal.IOSafeTerminal;
|
||||
|
||||
public interface ControlSequence {
|
||||
|
||||
default String getCode() {
|
||||
return "";
|
||||
}
|
||||
|
||||
default void applyTo(IOSafeTerminal terminal) {}
|
||||
|
||||
public static class NullControlSequence implements ControlSequence {}
|
||||
}
|
|
@ -1,25 +1,63 @@
|
|||
package terminal;
|
||||
|
||||
import static terminal.ControlSequenceHandler.Command.SGR;
|
||||
import static java.lang.Character.isDigit;
|
||||
import static terminal.ControlSequenceLookup.lookupControlSequence;
|
||||
import static util.Characters.*;
|
||||
|
||||
import terminal.SafeStream.SafeInputStream;
|
||||
|
||||
class ControlSequenceHandler {
|
||||
|
||||
private static final char ESCAPE = '\u001B';
|
||||
|
||||
public static final boolean isEscape(char c) {
|
||||
return c == '\u001B';
|
||||
return c == ESCAPE;
|
||||
}
|
||||
|
||||
private boolean inControlSequence;
|
||||
private int code;
|
||||
private Command command;
|
||||
private SafeInputStream input;
|
||||
private String code;
|
||||
private int currentCharacter;
|
||||
|
||||
public ControlSequenceHandler() {
|
||||
this.inControlSequence = false;
|
||||
this.code = 0;
|
||||
this.command = SGR;
|
||||
this.input = null;
|
||||
this.code = "";
|
||||
this.currentCharacter = 0;
|
||||
}
|
||||
|
||||
public static enum Command {
|
||||
SGR
|
||||
public ControlSequence parse(SafeInputStream inputStream) {
|
||||
input = inputStream;
|
||||
code = "";
|
||||
|
||||
readCharacter();
|
||||
if (isExpectedFirstCharacter())
|
||||
readCode();
|
||||
|
||||
return lookupControlSequence((char) currentCharacter, code);
|
||||
}
|
||||
|
||||
private void readCharacter() {
|
||||
currentCharacter = input.read();
|
||||
}
|
||||
|
||||
private boolean isExpectedFirstCharacter() {
|
||||
return isCharacter() && isLeftBracket();
|
||||
}
|
||||
|
||||
private boolean isCharacter() {
|
||||
return currentCharacter != EOF;
|
||||
}
|
||||
|
||||
private boolean isLeftBracket() {
|
||||
return (char) currentCharacter == LEFT_SQUARE_BRACKET;
|
||||
}
|
||||
|
||||
private void readCode() {
|
||||
for (readCharacter(); isPartOfCode(); readCharacter())
|
||||
code += (char) currentCharacter;
|
||||
}
|
||||
|
||||
private boolean isPartOfCode() {
|
||||
return isCharacter() && isDigit((char) currentCharacter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package terminal;
|
||||
|
||||
import static terminal.SelectGraphicRendition.SGR_COMMAND;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import terminal.ControlSequence.NullControlSequence;
|
||||
|
||||
public class ControlSequenceLookup {
|
||||
|
||||
private static Map<Character, Map<String, ControlSequence>> controlSequenceMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
Map<String, ControlSequence> selectGraphicRenditionMap = new HashMap<>();
|
||||
|
||||
for (SelectGraphicRendition sgr : SelectGraphicRendition.values())
|
||||
selectGraphicRenditionMap.put(sgr.getCode(), sgr);
|
||||
|
||||
controlSequenceMap.put(SGR_COMMAND, selectGraphicRenditionMap);
|
||||
}
|
||||
|
||||
public static ControlSequence lookupControlSequence(char command, String code) {
|
||||
Map<String, ControlSequence> commandMap = controlSequenceMap.getOrDefault(command, new HashMap<>());
|
||||
|
||||
return commandMap.getOrDefault(code, new NullControlSequence());
|
||||
}
|
||||
|
||||
}
|
|
@ -18,10 +18,10 @@ public class LispTerminal {
|
|||
public static final char END_OF_SEGMENT = 'x';
|
||||
|
||||
private IOSafeTerminal terminal;
|
||||
private SafePipedOutputStream inputWriter;
|
||||
private SafePipedInputStream outputReader;
|
||||
private ExecutorService executorService;
|
||||
private SafeOutputStream inputWriter;
|
||||
private SafeInputStream outputReader;
|
||||
private ControlSequenceHandler controlSequenceHandler;
|
||||
private ExecutorService executorService;
|
||||
private TerminalSize terminalSize;
|
||||
private String inputLine;
|
||||
private String outputSegment;
|
||||
|
@ -31,20 +31,20 @@ public class LispTerminal {
|
|||
|
||||
public LispTerminal(IOSafeTerminal terminal, PipedOutputStream inputWriter, PipedInputStream outputReader) {
|
||||
this.terminal = terminal;
|
||||
this.inputWriter = new SafePipedOutputStream(inputWriter);
|
||||
this.outputReader = new SafePipedInputStream(outputReader);
|
||||
this.executorService = Executors.newFixedThreadPool(2);
|
||||
this.inputWriter = new SafeOutputStream(inputWriter);
|
||||
this.outputReader = new SafeInputStream(outputReader);
|
||||
this.controlSequenceHandler = new ControlSequenceHandler();
|
||||
this.executorService = Executors.newFixedThreadPool(2);
|
||||
this.terminalSize = terminal.getTerminalSize();
|
||||
this.inputLine = "";
|
||||
this.outputSegment = "";
|
||||
this.isStopped = false;
|
||||
|
||||
updateOrigin();
|
||||
setOriginToCurrentPosition();
|
||||
terminal.addResizeListener((t, newSize) -> resize());
|
||||
}
|
||||
|
||||
private synchronized void updateOrigin() {
|
||||
private synchronized void setOriginToCurrentPosition() {
|
||||
TerminalPosition cursorPosition = terminal.getCursorPosition();
|
||||
originColumn = cursorPosition.getColumn();
|
||||
originRow = cursorPosition.getRow();
|
||||
|
@ -54,12 +54,12 @@ public class LispTerminal {
|
|||
terminalSize = terminal.getTerminalSize();
|
||||
terminal.clearScreen();
|
||||
terminal.setCursorPosition(0, 0);
|
||||
updateOrigin();
|
||||
putString(inputLine);
|
||||
setOriginToCurrentPosition();
|
||||
putStringToTerminal(inputLine);
|
||||
moveCursorToEndOfInput();
|
||||
}
|
||||
|
||||
private synchronized void putString(String characters) {
|
||||
private synchronized void putStringToTerminal(String characters) {
|
||||
for (char c : characters.toCharArray())
|
||||
terminal.putCharacter(c);
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ public class LispTerminal {
|
|||
private void doControlC() {
|
||||
moveCursorToEndOfInput();
|
||||
terminal.putCharacter('\n');
|
||||
updateOrigin();
|
||||
setOriginToCurrentPosition();
|
||||
stop();
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ public class LispTerminal {
|
|||
inputWriter.write(inputLine.getBytes());
|
||||
inputWriter.flush();
|
||||
inputLine = "";
|
||||
updateOrigin();
|
||||
setOriginToCurrentPosition();
|
||||
}
|
||||
|
||||
private synchronized void doLeftArrow() {
|
||||
|
@ -257,7 +257,7 @@ public class LispTerminal {
|
|||
String remaining = inputLine.substring(distanceFromOrigin, inputLine.length());
|
||||
inputLine = inputLine.substring(0, distanceFromOrigin - 1) + remaining;
|
||||
moveCursorLeft(cursorPosition);
|
||||
putString(remaining + " ");
|
||||
putStringToTerminal(remaining + " ");
|
||||
moveCursorLeft(cursorPosition);
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ public class LispTerminal {
|
|||
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
|
||||
String remaining = inputLine.substring(distanceFromOrigin + 1, inputLine.length());
|
||||
inputLine = inputLine.substring(0, distanceFromOrigin) + remaining;
|
||||
putString(remaining + " ");
|
||||
putStringToTerminal(remaining + " ");
|
||||
terminal.setCursorPosition(cursorPosition);
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,7 @@ public class LispTerminal {
|
|||
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
|
||||
String remaining = character + inputLine.substring(distanceFromOrigin, inputLine.length());
|
||||
inputLine = inputLine.substring(0, distanceFromOrigin) + remaining;
|
||||
putString(remaining);
|
||||
putStringToTerminal(remaining);
|
||||
moveCursorRight(cursorPosition);
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,7 @@ public class LispTerminal {
|
|||
|
||||
private synchronized TerminalPosition adjustCursorPosition(TerminalPosition cursorPosition) {
|
||||
terminal.setCursorPosition(new TerminalPosition(originColumn, originRow));
|
||||
putString(inputLine);
|
||||
putStringToTerminal(inputLine);
|
||||
|
||||
return cursorPosition.withRelativeRow(-1);
|
||||
}
|
||||
|
@ -343,16 +343,12 @@ public class LispTerminal {
|
|||
}
|
||||
|
||||
private synchronized void processOutput(char c) {
|
||||
if (isEscape(c))
|
||||
parseControlSequence();
|
||||
else if (isEndOfSegment(c))
|
||||
if (isEndOfSegment(c))
|
||||
writeSegment();
|
||||
else
|
||||
outputSegment += c;
|
||||
}
|
||||
|
||||
private synchronized void parseControlSequence() {}
|
||||
|
||||
private synchronized boolean isEndOfSegment(char c) {
|
||||
return c == END_OF_SEGMENT;
|
||||
}
|
||||
|
@ -362,16 +358,31 @@ public class LispTerminal {
|
|||
printSegmentCharacters();
|
||||
terminal.setCursorVisible(true);
|
||||
outputSegment = "";
|
||||
updateOrigin();
|
||||
setOriginToCurrentPosition();
|
||||
}
|
||||
|
||||
private synchronized void printSegmentCharacters() {
|
||||
moveCursorToEndOfInput();
|
||||
putString(outputSegment);
|
||||
putOutputToTerminal();
|
||||
moveCursorToNextRowIfNecessary();
|
||||
terminal.flush();
|
||||
}
|
||||
|
||||
private synchronized void putOutputToTerminal() {
|
||||
SafeInputStream input = new SafeInputStream(new ByteArrayInputStream(outputSegment.getBytes()));
|
||||
|
||||
for (int c = input.read(); c != EOF; c = input.read())
|
||||
if (isEscape((char) c))
|
||||
applyControlSequence(input);
|
||||
else
|
||||
terminal.putCharacter((char) c);
|
||||
}
|
||||
|
||||
private void applyControlSequence(SafeInputStream input) {
|
||||
ControlSequence controlSequence = controlSequenceHandler.parse(input);
|
||||
controlSequence.applyTo(terminal);
|
||||
}
|
||||
|
||||
private synchronized void moveCursorToNextRowIfNecessary() {
|
||||
TerminalPosition cursorPosition = terminal.getCursorPosition();
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ import java.io.*;
|
|||
|
||||
public interface SafeStream {
|
||||
|
||||
public static class SafePipedInputStream {
|
||||
public static class SafeInputStream {
|
||||
|
||||
private PipedInputStream underlyingStream;
|
||||
private InputStream underlyingStream;
|
||||
|
||||
public SafePipedInputStream(PipedInputStream underlyingStream) {
|
||||
public SafeInputStream(InputStream underlyingStream) {
|
||||
this.underlyingStream = underlyingStream;
|
||||
}
|
||||
|
||||
|
@ -29,11 +29,11 @@ public interface SafeStream {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SafePipedOutputStream {
|
||||
public static class SafeOutputStream {
|
||||
|
||||
private PipedOutputStream underlyingStream;
|
||||
private OutputStream underlyingStream;
|
||||
|
||||
public SafePipedOutputStream(PipedOutputStream underlyingStream) {
|
||||
public SafeOutputStream(OutputStream underlyingStream) {
|
||||
this.underlyingStream = underlyingStream;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package terminal;
|
||||
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.terminal.IOSafeTerminal;
|
||||
|
||||
public enum SelectGraphicRendition implements ControlSequence {
|
||||
|
||||
RESET {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(IOSafeTerminal terminal) {
|
||||
terminal.resetColorAndSGR();
|
||||
}
|
||||
},
|
||||
|
||||
RED {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "31";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(IOSafeTerminal terminal) {
|
||||
terminal.setForegroundColor(TextColor.ANSI.RED);
|
||||
}
|
||||
},
|
||||
|
||||
GREEN {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "32";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(IOSafeTerminal terminal) {
|
||||
terminal.setForegroundColor(TextColor.ANSI.GREEN);
|
||||
}
|
||||
},
|
||||
|
||||
YELLOW {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "33";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(IOSafeTerminal terminal) {
|
||||
terminal.setForegroundColor(TextColor.ANSI.YELLOW);
|
||||
}
|
||||
},
|
||||
|
||||
PURPLE {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "35";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(IOSafeTerminal terminal) {
|
||||
terminal.setForegroundColor(TextColor.ANSI.MAGENTA);
|
||||
}
|
||||
};
|
||||
|
||||
public static final char SGR_COMMAND = 'm';
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package terminal;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static terminal.ControlSequenceHandler.isEscape;
|
||||
import static terminal.SelectGraphicRendition.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import terminal.ControlSequence.NullControlSequence;
|
||||
import terminal.SafeStream.SafeInputStream;
|
||||
import testutil.TestUtilities;
|
||||
import util.Characters;
|
||||
|
||||
public class ControlSequenceHandlerTest {
|
||||
|
||||
private ControlSequenceHandler handler;
|
||||
|
||||
private Object readRemaining(SafeInputStream input) {
|
||||
String remaining = "";
|
||||
|
||||
for (int c = input.read(); c != Characters.EOF; c = input.read())
|
||||
remaining += (char) c;
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
private SafeInputStream createSafeInputStream(String data) {
|
||||
return new SafeInputStream(TestUtilities.createInputStreamFromString(data));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
handler = new ControlSequenceHandler();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEscapeDetectsNonEscapeCharacter() {
|
||||
assertFalse(isEscape('x'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEscapeDetectsEscapeCharacter() {
|
||||
assertTrue(isEscape('\u001b'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctlyParsesControlSequence_LeavesRestOfStreamIntact() {
|
||||
SafeInputStream input = createSafeInputStream("[32mdata");
|
||||
handler.parse(input);
|
||||
assertEquals("data", readRemaining(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unterminatedControlSequence_OnlyConsumesFirstNonSequenceCharacter() {
|
||||
SafeInputStream input = createSafeInputStream("[32data");
|
||||
handler.parse(input);
|
||||
assertEquals("ata", readRemaining(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedControlSequence_OnlyConsumesOneCharacter() {
|
||||
SafeInputStream input = createSafeInputStream("32mdata");
|
||||
handler.parse(input);
|
||||
assertEquals("2mdata", readRemaining(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_EOF() {
|
||||
SafeInputStream input = createSafeInputStream("");
|
||||
assertTrue(handler.parse(input) instanceof NullControlSequence);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_EOF_AfterFirstCharacter() {
|
||||
SafeInputStream input = createSafeInputStream("[");
|
||||
assertTrue(handler.parse(input) instanceof NullControlSequence);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_UnterminatedControlSequence() {
|
||||
SafeInputStream input = createSafeInputStream("[data");
|
||||
assertTrue(handler.parse(input) instanceof NullControlSequence);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_MalformedControlSequence() {
|
||||
SafeInputStream input = createSafeInputStream("32mdata");
|
||||
assertTrue(handler.parse(input) instanceof NullControlSequence);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_SGR_Reset() {
|
||||
SafeInputStream input = createSafeInputStream("[0m");
|
||||
assertEquals(RESET, handler.parse(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_SGR_Red() {
|
||||
SafeInputStream input = createSafeInputStream("[31m");
|
||||
assertEquals(RED, handler.parse(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_SGR_Green() {
|
||||
SafeInputStream input = createSafeInputStream("[32m");
|
||||
assertEquals(GREEN, handler.parse(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_SGR_Yellow() {
|
||||
SafeInputStream input = createSafeInputStream("[33m");
|
||||
assertEquals(YELLOW, handler.parse(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsedControlSequenceIsCorrectType_SGR_Purple() {
|
||||
SafeInputStream input = createSafeInputStream("[35m");
|
||||
assertEquals(PURPLE, handler.parse(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseMultipleControlSequences() {
|
||||
SafeInputStream input = createSafeInputStream("[35m[32m[0m");
|
||||
assertEquals(PURPLE, handler.parse(input));
|
||||
assertEquals(GREEN, handler.parse(input));
|
||||
assertEquals(RESET, handler.parse(input));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package terminal;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static terminal.SelectGraphicRendition.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.terminal.virtual.*;
|
||||
|
||||
import terminal.ControlSequence.NullControlSequence;
|
||||
|
||||
public class ControlSequenceTest {
|
||||
|
||||
private Set<String> indicatorSet;
|
||||
|
||||
private VirtualTerminal createTerminalWithIndicators() {
|
||||
return new DefaultVirtualTerminal() {
|
||||
|
||||
@Override
|
||||
public void resetColorAndSGR() {
|
||||
indicatorSet.add("RESET");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForegroundColor(TextColor color) {
|
||||
indicatorSet.add(color.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
indicatorSet = new HashSet<>();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullControlSequenceDoesNothing() {
|
||||
ControlSequence nullControlSequence = new NullControlSequence();
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
nullControlSequence.applyTo(terminal);
|
||||
assertTrue(indicatorSet.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlSequenceUpdatesTerminal_SGR_Reset() {
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
RESET.applyTo(terminal);
|
||||
assertTrue(indicatorSet.contains("RESET"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlSequenceUpdatesTerminal_SGR_Red() {
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
RED.applyTo(terminal);
|
||||
assertTrue(indicatorSet.contains("RED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlSequenceUpdatesTerminal_SGR_Green() {
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
GREEN.applyTo(terminal);
|
||||
assertTrue(indicatorSet.contains("GREEN"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlSequenceUpdatesTerminal_SGR_Yellow() {
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
YELLOW.applyTo(terminal);
|
||||
assertTrue(indicatorSet.contains("YELLOW"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlSequenceUpdatesTerminal_SGR_Purple() {
|
||||
VirtualTerminal terminal = createTerminalWithIndicators();
|
||||
PURPLE.applyTo(terminal);
|
||||
assertTrue(indicatorSet.contains("MAGENTA"));
|
||||
}
|
||||
|
||||
}
|
|
@ -507,5 +507,11 @@ public class LispTerminalTest {
|
|||
assertCursorPosition(0, 0);
|
||||
assertCharacterPositions(new char[][] { { ' ', ' ', ' ' }, { ' ', ' ', ' ' } });
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void controlSequenceIsNotPrinted() {
|
||||
produceOutput("\u001B[32mcontrol\u001B[0mseq");
|
||||
assertCharacterPositions(new char[][] { { 'c', 'o', 'n', 't', 'r', 'o', 'l', 's', 'e', 'q' } });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue