Refactor main interpreter code

Fixed several minor issues

Only print the last value when interpreting a file

Resolves #4
This commit is contained in:
Mike Cifelli 2017-03-21 15:03:16 -04:00
parent 5cb6212d2a
commit 058e937c3e
11 changed files with 187 additions and 133 deletions

View File

@ -21,7 +21,7 @@ public class RuntimeEnvironment {
private String path; private String path;
private Runnable terminationFunction; private Runnable terminationFunction;
private Runnable errorTerminationFunction; private Runnable errorTerminationFunction;
private Function<String, String> outputDecorator; private Function<String, String> promptDecorator;
private Function<String, String> valueOutputDecorator; private Function<String, String> valueOutputDecorator;
private Function<String, String> warningOutputDecorator; private Function<String, String> warningOutputDecorator;
private Function<String, String> errorOutputDecorator; private Function<String, String> errorOutputDecorator;
@ -40,7 +40,7 @@ public class RuntimeEnvironment {
path = null; path = null;
terminationFunction = null; terminationFunction = null;
errorTerminationFunction = null; errorTerminationFunction = null;
outputDecorator = null; promptDecorator = null;
valueOutputDecorator = null; valueOutputDecorator = null;
warningOutputDecorator = null; warningOutputDecorator = null;
errorOutputDecorator = null; errorOutputDecorator = null;
@ -79,8 +79,8 @@ public class RuntimeEnvironment {
this.errorTerminationFunction = errorTerminationFunction; this.errorTerminationFunction = errorTerminationFunction;
} }
public void setOutputDecorator(Function<String, String> outputDecorator) { public void setPromptDecorator(Function<String, String> promptDecorator) {
this.outputDecorator = outputDecorator; this.promptDecorator = promptDecorator;
} }
public void setValueOutputDecorator(Function<String, String> valueOutputDecorator) { public void setValueOutputDecorator(Function<String, String> valueOutputDecorator) {
@ -131,8 +131,8 @@ public class RuntimeEnvironment {
errorTerminationFunction.run(); errorTerminationFunction.run();
} }
public String decorateOutput(String output) { public String decoratePrompt(String prompt) {
return outputDecorator.apply(output); return promptDecorator.apply(prompt);
} }
public String decorateValueOutput(String valueOutput) { public String decorateValueOutput(String valueOutput) {

View File

@ -1,11 +1,29 @@
package interpreter; package interpreter;
import sexpression.SExpression;
public class FileLispInterpreter extends LispInterpreter { public class FileLispInterpreter extends LispInterpreter {
private SExpression lastSExpression;
public FileLispInterpreter() {
this.lastSExpression = null;
}
@Override @Override
protected void afterInterpreting() { protected SExpression evaluateNextSExpression() {
environment.getOutput().println(); return this.lastSExpression = super.evaluateNextSExpression();
environment.getOutput().close(); }
@Override
protected void printSExpression(SExpression sExpression) {}
@Override
protected void applyFinishingTouches() {
if (lastSExpression != null)
super.printSExpression(lastSExpression);
super.applyFinishingTouches();
} }
} }

View File

@ -1,34 +1,28 @@
package interpreter; package interpreter;
import sexpression.SExpression;
public class InteractiveLispInterpreter extends LispInterpreter { public class InteractiveLispInterpreter extends LispInterpreter {
private static final String GREETING = "Transcendental Lisp - Version 1.0.0";
private static final String PROMPT = "~ "; private static final String PROMPT = "~ ";
@Override
protected void beforeInterpreting() {
environment.getOutput().println(GREETING);
environment.getOutput().println();
environment.getOutput().flush();
}
@Override @Override
protected void prompt() { protected void prompt() {
environment.getOutput().print(environment.decorateOutput(PROMPT)); environment.getOutput().print(environment.decoratePrompt(PROMPT));
environment.getOutput().flush(); environment.getOutput().flush();
} }
@Override @Override
protected void printValueOfNextSExpression() { protected void printSExpression(SExpression sExpression) {
environment.getOutput().println(); environment.getOutput().println();
super.printValueOfNextSExpression(); super.printSExpression(sExpression);
} }
@Override @Override
protected void afterInterpreting() { protected void applyFinishingTouches() {
environment.getOutput().println(); environment.getOutput().println();
environment.getOutput().println(); environment.getOutput().println(environment.decoratePrompt(""));
environment.getOutput().close(); environment.getOutput().flush();
} }
} }

View File

@ -18,39 +18,44 @@ public class LispInterpreter {
public void interpret() { public void interpret() {
createParser(); createParser();
beforeInterpreting();
for (prompt(); !parser.isEof(); prompt()) for (prompt(); !parser.isEof(); prompt())
printValueOfNextSExpression(); evaluateAndPrintNextSExpression();
afterInterpreting(); applyFinishingTouches();
} }
private void createParser() { private void createParser() {
parser = new LispParser(environment.getInput(), environment.getInputName()); parser = new LispParser(environment.getInput(), environment.getInputName());
} }
protected void beforeInterpreting() {}
protected void prompt() {} protected void prompt() {}
protected void printValueOfNextSExpression() { private void evaluateAndPrintNextSExpression() {
try { try {
printValueOfNextSExpressionWithException(); evaluateAndPrintNextSExpressionWithException();
} catch (LispException e) { } catch (LispException e) {
environment.getErrorManager().handle(e); environment.getErrorManager().handle(e);
} }
} }
private void printValueOfNextSExpressionWithException() { private void evaluateAndPrintNextSExpressionWithException() {
SExpression sExpression = parser.getNextSExpression(); printSExpression(evaluateNextSExpression());
String result = environment.decorateValueOutput(String.valueOf(eval(sExpression))); }
protected SExpression evaluateNextSExpression() {
SExpression sExpression = parser.getNextSExpression();
return eval(sExpression);
}
protected void printSExpression(SExpression sExpression) {
String result = environment.decorateValueOutput(String.valueOf(sExpression));
environment.getOutput().println(result); environment.getOutput().println(result);
environment.getOutput().flush(); environment.getOutput().flush();
} }
protected void afterInterpreting() { protected void applyFinishingTouches() {
environment.getOutput().println(); environment.getOutput().println();
environment.getOutput().flush(); environment.getOutput().flush();
} }

View File

@ -19,15 +19,15 @@ public interface LispInterpreterBuilder {
void useFile(String fileName); void useFile(String fileName);
void setOutputDecorator(Function<String, String> outputDecorator); void setPromptDecorator(Function<String, String> decorator);
void setValueOutputDecorator(Function<String, String> valueOutputDecorator); void setValueOutputDecorator(Function<String, String> decorator);
void setWarningOutputDecorator(Function<String, String> warningOutputDecorator); void setWarningOutputDecorator(Function<String, String> decorator);
void setErrorOutputDecorator(Function<String, String> errorOutputDecorator); void setErrorOutputDecorator(Function<String, String> decorator);
void setCriticalOutputDecorator(Function<String, String> criticalOutputDecorator); void setCriticalOutputDecorator(Function<String, String> decorator);
LispInterpreter build(); LispInterpreter build();

View File

@ -22,7 +22,7 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
private PrintStream errorOutputStream; private PrintStream errorOutputStream;
private Runnable terminationFunction; private Runnable terminationFunction;
private Runnable errorTerminationFunction; private Runnable errorTerminationFunction;
private Function<String, String> outputDecorator; private Function<String, String> promptDecorator;
private Function<String, String> valueOutputDecorator; private Function<String, String> valueOutputDecorator;
private Function<String, String> warningOutputDecorator; private Function<String, String> warningOutputDecorator;
private Function<String, String> errorOutputDecorator; private Function<String, String> errorOutputDecorator;
@ -38,7 +38,7 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
this.isInteractive = true; this.isInteractive = true;
this.isFileBased = false; this.isFileBased = false;
this.isBuilt = false; this.isBuilt = false;
this.outputDecorator = s -> s; this.promptDecorator = s -> s;
this.valueOutputDecorator = s -> s; this.valueOutputDecorator = s -> s;
this.warningOutputDecorator = s -> s; this.warningOutputDecorator = s -> s;
this.errorOutputDecorator = s -> s; this.errorOutputDecorator = s -> s;
@ -85,8 +85,8 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
} }
@Override @Override
public void setOutputDecorator(Function<String, String> decorator) { public void setPromptDecorator(Function<String, String> decorator) {
this.outputDecorator = decorator; this.promptDecorator = decorator;
} }
@Override @Override
@ -135,7 +135,7 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
environment.setErrorManager(errorManager); environment.setErrorManager(errorManager);
environment.setTerminationFunction(terminationFunction); environment.setTerminationFunction(terminationFunction);
environment.setErrorTerminationFunction(errorTerminationFunction); environment.setErrorTerminationFunction(errorTerminationFunction);
environment.setOutputDecorator(outputDecorator); environment.setPromptDecorator(promptDecorator);
environment.setValueOutputDecorator(valueOutputDecorator); environment.setValueOutputDecorator(valueOutputDecorator);
environment.setWarningOutputDecorator(warningOutputDecorator); environment.setWarningOutputDecorator(warningOutputDecorator);
environment.setErrorOutputDecorator(errorOutputDecorator); environment.setErrorOutputDecorator(errorOutputDecorator);

View File

@ -14,6 +14,7 @@ import terminal.SafeStream.UncheckedIOException;
public class LispMain { public class LispMain {
private static final String GREETING = "Transcendental Lisp - Version 1.0.1";
private static final String ANSI_RESET = "\u001B[0m"; private static final String ANSI_RESET = "\u001B[0m";
private static final String ANSI_RED = "\u001B[31m"; private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m"; private static final String ANSI_GREEN = "\u001B[32m";
@ -33,30 +34,55 @@ public class LispMain {
private PipedOutputStream inputWriter; private PipedOutputStream inputWriter;
private PipedInputStream outputReader; private PipedInputStream outputReader;
private PipedOutputStream outputWriter; private PipedOutputStream outputWriter;
private PrintStream outputStream;
private SafePipedOutputStream safeOutputWriter; private SafePipedOutputStream safeOutputWriter;
private LispTerminal lispTerminal; private LispTerminal lispTerminal;
private void runInteractive() {
initializeTerminalAndStreams();
printGreeting();
lispTerminal.start();
buildInteractiveInterpreter().interpret();
outputStream.close();
}
private void initializeTerminalAndStreams() {
try {
initalizeTerminalAndStreamsWithException();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void initalizeTerminalAndStreamsWithException() throws IOException {
inputReader = new PipedInputStream();
inputWriter = new PipedOutputStream(inputReader);
outputReader = new PipedInputStream();
outputWriter = new PipedOutputStream(outputReader);
outputStream = new PrintStream(outputWriter);
safeOutputWriter = new SafePipedOutputStream(outputWriter);
lispTerminal = new LispTerminal(createIOSafeTerminal(), inputWriter, outputReader);
}
private IOSafeTerminal createIOSafeTerminal() throws IOException { private IOSafeTerminal createIOSafeTerminal() throws IOException {
Terminal defaultTerminal = new DefaultTerminalFactory().createTerminal(); Terminal defaultTerminal = new DefaultTerminalFactory().createTerminal();
return IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter(defaultTerminal); return IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter(defaultTerminal);
} }
private void runInteractive() { private void printGreeting() {
initializeTerminal(); outputStream.println(GREETING);
lispTerminal.start(); outputStream.println();
buildInteractiveInterpreter().interpret();
} }
private LispInterpreter buildInteractiveInterpreter() { private LispInterpreter buildInteractiveInterpreter() {
LispInterpreterBuilder builder = LispInterpreterBuilderImpl.getInstance(); LispInterpreterBuilder builder = LispInterpreterBuilderImpl.getInstance();
PrintStream outputStream = new PrintStream(outputWriter);
builder.setInput(inputReader, "terminal"); builder.setInput(inputReader, "terminal");
builder.setOutput(outputStream); builder.setOutput(outputStream);
builder.setErrorOutput(outputStream); builder.setErrorOutput(outputStream);
builder.setTerminationFunction(this::shutdown); builder.setTerminationFunction(this::shutdown);
builder.setErrorTerminationFunction(this::shutdown); builder.setErrorTerminationFunction(this::shutdown);
builder.setOutputDecorator(makeInteractiveDecorator(ANSI_GREEN)); builder.setPromptDecorator(makeSegmentDecorator(ANSI_GREEN));
builder.setValueOutputDecorator(s -> s); builder.setValueOutputDecorator(s -> s);
builder.setWarningOutputDecorator(s -> s); builder.setWarningOutputDecorator(s -> s);
builder.setErrorOutputDecorator(s -> s); builder.setErrorOutputDecorator(s -> s);
@ -66,11 +92,13 @@ public class LispMain {
} }
private void shutdown() { private void shutdown() {
outputStream.println();
outputStream.println(END_OF_SEGMENT);
lispTerminal.stop(); lispTerminal.stop();
safeOutputWriter.close(); safeOutputWriter.close();
} }
private static Function<String, String> makeInteractiveDecorator(String color) { private static Function<String, String> makeSegmentDecorator(String color) {
return new Function<String, String>() { return new Function<String, String>() {
@Override @Override
@ -80,23 +108,6 @@ public class LispMain {
}; };
} }
private void initializeTerminal() {
try {
initalizeTerminalWithException();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void initalizeTerminalWithException() throws IOException {
inputReader = new PipedInputStream();
inputWriter = new PipedOutputStream(inputReader);
outputReader = new PipedInputStream();
outputWriter = new PipedOutputStream(outputReader);
safeOutputWriter = new SafePipedOutputStream(outputWriter);
lispTerminal = new LispTerminal(createIOSafeTerminal(), inputWriter, outputReader);
}
private void runWithFile(String fileName) { private void runWithFile(String fileName) {
buildFileInterpreter(fileName).interpret(); buildFileInterpreter(fileName).interpret();
} }
@ -108,7 +119,6 @@ public class LispMain {
builder.setErrorOutput(System.err); builder.setErrorOutput(System.err);
builder.setTerminationFunction(() -> System.exit(0)); builder.setTerminationFunction(() -> System.exit(0));
builder.setErrorTerminationFunction(() -> System.exit(1)); builder.setErrorTerminationFunction(() -> System.exit(1));
builder.setOutputDecorator(makeColorDecorator(ANSI_GREEN));
builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN)); builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN));
builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW)); builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW));
builder.setErrorOutputDecorator(makeColorDecorator(ANSI_RED)); builder.setErrorOutputDecorator(makeColorDecorator(ANSI_RED));

View File

@ -100,17 +100,23 @@ public class LispTerminal {
private KeyStroke getKeyStroke() { private KeyStroke getKeyStroke() {
KeyStroke keyStroke = null; KeyStroke keyStroke = null;
// issue #299
try { try {
keyStroke = terminal.pollInput(); keyStroke = terminal.pollInput();
} catch (IllegalStateException e) { // issue #299 } catch (IllegalStateException e) {
moveCursorToEndOfInput(); doControlC();
terminal.putCharacter('\n');
stop();
} }
return keyStroke; return keyStroke;
} }
private void doControlC() {
moveCursorToEndOfInput();
terminal.putCharacter('\n');
updateOrigin();
stop();
}
private synchronized void handleKey(KeyStroke keyStroke) { private synchronized void handleKey(KeyStroke keyStroke) {
doKey(keyStroke); doKey(keyStroke);
terminal.flush(); terminal.flush();
@ -324,9 +330,7 @@ public class LispTerminal {
private void takeNap() { private void takeNap() {
try { try {
Thread.sleep(1); Thread.sleep(1);
} catch (InterruptedException e) { } catch (InterruptedException ignored) {}
isStopped = true;
}
} }
private void writeOutput() { private void writeOutput() {

View File

@ -91,10 +91,10 @@ public class RuntimeEnvironmentTest {
} }
@Test @Test
public void assignOutputDecorator() { public void assignPromptDecorator() {
environment.setOutputDecorator(s -> "[" + s + "]"); environment.setPromptDecorator(s -> "[" + s + "]");
assertEquals("[test]", environment.decorateOutput("test")); assertEquals("[test]", environment.decoratePrompt("test"));
} }
@Test @Test
@ -135,7 +135,7 @@ public class RuntimeEnvironmentTest {
environment.setPath("testpath/"); environment.setPath("testpath/");
environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY)); environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY));
environment.setErrorTerminationFunction(() -> indicatorSet.add(TERMINATED_EXCEPTIONALLY)); environment.setErrorTerminationFunction(() -> indicatorSet.add(TERMINATED_EXCEPTIONALLY));
environment.setOutputDecorator(s -> "[" + s + "]"); environment.setPromptDecorator(s -> "[" + s + "]");
environment.setValueOutputDecorator(s -> "(" + s + ")"); environment.setValueOutputDecorator(s -> "(" + s + ")");
environment.setWarningOutputDecorator(s -> "|" + s + "|"); environment.setWarningOutputDecorator(s -> "|" + s + "|");
environment.setErrorOutputDecorator(s -> "{" + s + "}"); environment.setErrorOutputDecorator(s -> "{" + s + "}");
@ -160,8 +160,8 @@ public class RuntimeEnvironmentTest {
} catch (NullPointerException e) {} } catch (NullPointerException e) {}
try { try {
environment.decorateOutput(""); environment.decoratePrompt("");
fail("decorateOutput"); fail("decoratePrompt");
} catch (NullPointerException e) {} } catch (NullPointerException e) {}
try { try {

View File

@ -47,7 +47,6 @@ public class LOADTest {
environment.setErrorOutput(new PrintStream(errorOutputStream)); environment.setErrorOutput(new PrintStream(errorOutputStream));
environment.setErrorManager(new ErrorManager()); environment.setErrorManager(new ErrorManager());
environment.setPath(""); environment.setPath("");
environment.setOutputDecorator(s -> s);
environment.setWarningOutputDecorator(s -> s); environment.setWarningOutputDecorator(s -> s);
environment.setErrorOutputDecorator(s -> s); environment.setErrorOutputDecorator(s -> s);
} }

View File

@ -1,5 +1,6 @@
package terminal; package terminal;
import static com.googlecode.lanterna.input.KeyType.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static terminal.LispTerminal.END_OF_SEGMENT; import static terminal.LispTerminal.END_OF_SEGMENT;
@ -146,7 +147,7 @@ public class LispTerminalTest {
@Test @Test
public void leftArrowDoesNotMovePastOrigin() { public void leftArrowDoesNotMovePastOrigin() {
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
} }
@ -154,13 +155,13 @@ public class LispTerminalTest {
public void leftArrowWorksAfterEnteringCharacters() { public void leftArrowWorksAfterEnteringCharacters() {
enterCharacters("abc"); enterCharacters("abc");
assertCursorPosition(3, 0); assertCursorPosition(3, 0);
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(1, 0); assertCursorPosition(1, 0);
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
} }
@ -169,13 +170,13 @@ public class LispTerminalTest {
setColumns(5); setColumns(5);
enterCharacters("123451"); enterCharacters("123451");
assertCursorPosition(1, 1); assertCursorPosition(1, 1);
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
assertCursorPosition(4, 0); assertCursorPosition(4, 0);
} }
@Test @Test
public void rightArrowDoesNotMovePastEndOfInput() { public void rightArrowDoesNotMovePastEndOfInput() {
pressKey(KeyType.ArrowRight); pressKey(ArrowRight);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
} }
@ -183,11 +184,11 @@ public class LispTerminalTest {
public void rightArrowWorksAfterMovingLeft() { public void rightArrowWorksAfterMovingLeft() {
enterCharacters("12"); enterCharacters("12");
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
pressKey(KeyType.ArrowLeft); pressKey(ArrowLeft);
assertCursorPosition(1, 0); assertCursorPosition(1, 0);
pressKey(KeyType.ArrowRight); pressKey(ArrowRight);
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
pressKey(KeyType.ArrowRight); pressKey(ArrowRight);
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
} }
@ -196,9 +197,9 @@ public class LispTerminalTest {
setColumns(5); setColumns(5);
enterCharacters("123451"); enterCharacters("123451");
assertCursorPosition(1, 1); assertCursorPosition(1, 1);
pressKeyTimes(KeyType.ArrowLeft, 3); pressKeyTimes(ArrowLeft, 3);
assertCursorPosition(3, 0); assertCursorPosition(3, 0);
pressKeyTimes(KeyType.ArrowRight, 3); pressKeyTimes(ArrowRight, 3);
assertCursorPosition(1, 1); assertCursorPosition(1, 1);
} }
@ -212,7 +213,7 @@ public class LispTerminalTest {
@Test @Test
public void characterIsInserted() { public void characterIsInserted() {
enterCharacters("abcd"); enterCharacters("abcd");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
enterCharacter('x'); enterCharacter('x');
assertCharacterPositions(new char[][] { { 'a', 'b', 'x', 'c', 'd' } }); assertCharacterPositions(new char[][] { { 'a', 'b', 'x', 'c', 'd' } });
} }
@ -221,21 +222,21 @@ public class LispTerminalTest {
public void characterIsInserted_PushesInputToNextRow() { public void characterIsInserted_PushesInputToNextRow() {
setColumns(4); setColumns(4);
enterCharacters("abcd"); enterCharacters("abcd");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
enterCharacter('x'); enterCharacter('x');
assertCharacterPositions(new char[][] { { 'a', 'b', 'x', 'c' }, { 'd', ' ', ' ', ' ' } }); assertCharacterPositions(new char[][] { { 'a', 'b', 'x', 'c' }, { 'd', ' ', ' ', ' ' } });
} }
@Test @Test
public void backspaceDoesNothingAtOrigin() { public void backspaceDoesNothingAtOrigin() {
pressKey(KeyType.Backspace); pressKey(Backspace);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
} }
@Test @Test
public void backspaceWorksAfterInput() { public void backspaceWorksAfterInput() {
enterCharacters("12345"); enterCharacters("12345");
pressKeyTimes(KeyType.Backspace, 2); pressKeyTimes(Backspace, 2);
assertCursorPosition(3, 0); assertCursorPosition(3, 0);
assertCharacterPositions(new char[][] { { '1', '2', '3', ' ', ' ', ' ' } }); assertCharacterPositions(new char[][] { { '1', '2', '3', ' ', ' ', ' ' } });
} }
@ -244,7 +245,7 @@ public class LispTerminalTest {
public void backspaceWorksAcrossRow() { public void backspaceWorksAcrossRow() {
setColumns(4); setColumns(4);
enterCharacters("1234567"); enterCharacters("1234567");
pressKeyTimes(KeyType.Backspace, 5); pressKeyTimes(Backspace, 5);
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
assertCharacterPositions(new char[][] { { '1', '2', ' ', ' ' }, { ' ', ' ', ' ', ' ' } }); assertCharacterPositions(new char[][] { { '1', '2', ' ', ' ' }, { ' ', ' ', ' ', ' ' } });
} }
@ -252,22 +253,22 @@ public class LispTerminalTest {
@Test @Test
public void backspaceWorksInMiddleOfInput() { public void backspaceWorksInMiddleOfInput() {
enterCharacters("12345"); enterCharacters("12345");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
pressKey(KeyType.Backspace); pressKey(Backspace);
assertCursorPosition(2, 0); assertCursorPosition(2, 0);
assertCharacterPositions(new char[][] { { '1', '2', '4', '5' } }); assertCharacterPositions(new char[][] { { '1', '2', '4', '5' } });
} }
@Test @Test
public void deleteDoesNothingAtOrigin() { public void deleteDoesNothingAtOrigin() {
pressKey(KeyType.Delete); pressKey(Delete);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
} }
@Test @Test
public void deleteDoesNothingAtEndOfInput() { public void deleteDoesNothingAtEndOfInput() {
enterCharacters("del"); enterCharacters("del");
pressKey(KeyType.Delete); pressKey(Delete);
assertCursorPosition(3, 0); assertCursorPosition(3, 0);
assertCharacterPositions(new char[][] { { 'd', 'e', 'l' } }); assertCharacterPositions(new char[][] { { 'd', 'e', 'l' } });
} }
@ -275,8 +276,8 @@ public class LispTerminalTest {
@Test @Test
public void deleteWorksAtStartOfInput() { public void deleteWorksAtStartOfInput() {
enterCharacters("del"); enterCharacters("del");
pressKeyTimes(KeyType.ArrowLeft, 3); pressKeyTimes(ArrowLeft, 3);
pressKeyTimes(KeyType.Delete, 3); pressKeyTimes(Delete, 3);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
assertCharacterPositions(new char[][] { { ' ', ' ', ' ' } }); assertCharacterPositions(new char[][] { { ' ', ' ', ' ' } });
} }
@ -285,56 +286,56 @@ public class LispTerminalTest {
public void deleteWorksAcrossRow() { public void deleteWorksAcrossRow() {
setColumns(4); setColumns(4);
enterCharacters("delete"); enterCharacters("delete");
pressKeyTimes(KeyType.ArrowLeft, 5); pressKeyTimes(ArrowLeft, 5);
pressKey(KeyType.Delete); pressKey(Delete);
assertCursorPosition(1, 0); assertCursorPosition(1, 0);
assertCharacterPositions(new char[][] { { 'd', 'l', 'e', 't' }, { 'e', ' ' } }); assertCharacterPositions(new char[][] { { 'd', 'l', 'e', 't' }, { 'e', ' ' } });
} }
@Test @Test
public void enterMovesToNextLine() { public void enterMovesToNextLine() {
pressKey(KeyType.Enter); pressKey(Enter);
assertCursorPosition(0, 1); assertCursorPosition(0, 1);
} }
@Test @Test
public void enterWritesLineToPipedStream() { public void enterWritesLineToPipedStream() {
enterCharacters("enter"); enterCharacters("enter");
pressKey(KeyType.Enter); pressKey(Enter);
assertInputWritten("enter\n"); assertInputWritten("enter\n");
} }
@Test @Test
public void enterPressedInMiddleOfInput_WritesEntireLineToPipedStream() { public void enterPressedInMiddleOfInput_WritesEntireLineToPipedStream() {
enterCharacters("enter"); enterCharacters("enter");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
pressKey(KeyType.Enter); pressKey(Enter);
assertInputWritten("enter\n"); assertInputWritten("enter\n");
} }
@Test @Test
public void enterAfterInsertedText_WritesLineToPipedStream() { public void enterAfterInsertedText_WritesLineToPipedStream() {
enterCharacters("enter"); enterCharacters("enter");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
enterCharacters("||"); enterCharacters("||");
pressKey(KeyType.Enter); pressKey(Enter);
assertInputWritten("ent||er\n"); assertInputWritten("ent||er\n");
} }
@Test @Test
public void enterAfterBackspace_WritesLineToPipedStream() { public void enterAfterBackspace_WritesLineToPipedStream() {
enterCharacters("enter"); enterCharacters("enter");
pressKeyTimes(KeyType.Backspace, 2); pressKeyTimes(Backspace, 2);
pressKey(KeyType.Enter); pressKey(Enter);
assertInputWritten("ent\n"); assertInputWritten("ent\n");
} }
@Test @Test
public void enterAfterDelete_WritesLineToPipedStream() { public void enterAfterDelete_WritesLineToPipedStream() {
enterCharacters("enter"); enterCharacters("enter");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
pressKeyTimes(KeyType.Delete, 2); pressKeyTimes(Delete, 2);
pressKey(KeyType.Enter); pressKey(Enter);
assertInputWritten("ent\n"); assertInputWritten("ent\n");
} }
@ -349,7 +350,7 @@ public class LispTerminalTest {
@Test @Test
public void controlDWorksInMiddleOfInput() { public void controlDWorksInMiddleOfInput() {
enterCharacters("control-d"); enterCharacters("control-d");
pressKeyTimes(KeyType.ArrowLeft, 2); pressKeyTimes(ArrowLeft, 2);
enterControlCharacter('d'); enterControlCharacter('d');
assertInputStreamClosed(); assertInputStreamClosed();
assertInputWritten("control-d\n"); assertInputWritten("control-d\n");
@ -357,7 +358,7 @@ public class LispTerminalTest {
@Test @Test
public void escapeDoesNothing() { public void escapeDoesNothing() {
pressKey(KeyType.Escape); pressKey(Escape);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
assertInputWritten(""); assertInputWritten("");
} }
@ -371,7 +372,7 @@ public class LispTerminalTest {
@Test @Test
public void controlEnterDoesNothing() { public void controlEnterDoesNothing() {
pressControlKey(KeyType.Enter); pressControlKey(Enter);
assertCursorPosition(0, 0); assertCursorPosition(0, 0);
assertInputWritten(""); assertInputWritten("");
} }
@ -403,9 +404,9 @@ public class LispTerminalTest {
public void insertingTextPushesInputPastEndOfBuffer() { public void insertingTextPushesInputPastEndOfBuffer() {
setColumns(3); setColumns(3);
setRows(4); setRows(4);
pressKey(KeyType.Enter); pressKey(Enter);
enterCharacters("00011122"); enterCharacters("00011122");
pressKeyTimes(KeyType.ArrowLeft, 4); pressKeyTimes(ArrowLeft, 4);
assertCursorPosition(1, 2); assertCursorPosition(1, 2);
enterCharacters("zz"); enterCharacters("zz");
assertCursorPosition(0, 2); assertCursorPosition(0, 2);
@ -418,7 +419,7 @@ public class LispTerminalTest {
setColumns(3); setColumns(3);
setRows(3); setRows(3);
enterCharacters("00011122"); enterCharacters("00011122");
pressKeyTimes(KeyType.ArrowLeft, 4); pressKeyTimes(ArrowLeft, 4);
assertCursorPosition(1, 1); assertCursorPosition(1, 1);
enterCharacters("zz"); enterCharacters("zz");
assertCursorPosition(1, 1); assertCursorPosition(1, 1);
@ -454,7 +455,7 @@ public class LispTerminalTest {
public void printedOutputDoesNotOverwriteInput() { public void printedOutputDoesNotOverwriteInput() {
setColumns(3); setColumns(3);
enterCharacters("01201201"); enterCharacters("01201201");
pressKeyTimes(KeyType.ArrowLeft, 5); pressKeyTimes(ArrowLeft, 5);
produceOutput("out"); produceOutput("out");
assertCursorPosition(0, 4); assertCursorPosition(0, 4);
assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', 'o' }, assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', 'o' },
@ -465,8 +466,8 @@ public class LispTerminalTest {
public void printedOutputDoesNotOverwriteInput_AfterEnter() { public void printedOutputDoesNotOverwriteInput_AfterEnter() {
setColumns(3); setColumns(3);
enterCharacters("01201201"); enterCharacters("01201201");
pressKeyTimes(KeyType.ArrowLeft, 5); pressKeyTimes(ArrowLeft, 5);
pressKey(KeyType.Enter); pressKey(Enter);
produceOutput("out"); produceOutput("out");
assertCursorPosition(0, 4); assertCursorPosition(0, 4);
assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', ' ' }, assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', ' ' },
@ -476,12 +477,35 @@ public class LispTerminalTest {
@Test @Test
public void resizeIsHandledGracefully() { public void resizeIsHandledGracefully() {
enterCharacters("resize"); enterCharacters("resize");
pressKey(KeyType.Enter); pressKey(Enter);
enterCharacters("test"); enterCharacters("test");
setColumns(10); setColumns(3);
assertCursorPosition(4, 0); assertCursorPosition(1, 1);
assertCharacterPositions(new char[][] { { 't', 'e', 's', 't', ' ', ' ', ' ', ' ', ' ', ' ' }, assertCharacterPositions(new char[][] { { 't', 'e', 's' }, { 't', ' ', ' ' } });
{ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }); }
@Test
public void backspaceWorksAfterResize() {
enterCharacters("resize");
pressKey(Enter);
enterCharacters("test");
setColumns(3);
pressKeyTimes(Backspace, 20);
assertCursorPosition(0, 0);
assertCharacterPositions(new char[][] { { ' ', ' ', ' ' }, { ' ', ' ', ' ' } });
}
@Test
public void deleteWorksAfterResize() {
enterCharacters("resize");
pressKey(Enter);
enterCharacters("test");
setColumns(3);
pressKeyTimes(ArrowLeft, 20);
pressKeyTimes(Delete, 20);
pressKeyTimes(ArrowRight, 20);
assertCursorPosition(0, 0);
assertCharacterPositions(new char[][] { { ' ', ' ', ' ' }, { ' ', ' ', ' ' } });
} }
} }