Clean up terminal code

This commit is contained in:
Mike Cifelli 2017-03-21 09:25:40 -04:00
parent fc96894d14
commit a8eff1ad70
3 changed files with 165 additions and 153 deletions

View File

@ -41,7 +41,7 @@ public class LispMain {
private void run(String[] args) {
if (args.length == 0)
lispTerminal.run();
lispTerminal.start();
LispInterpreter interpreter = buildInterpreter(args);
interpreter.interpret();
@ -85,7 +85,7 @@ public class LispMain {
private void shutdown() {
try {
lispTerminal.finish();
lispTerminal.stop();
outputWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block

View File

@ -1,5 +1,6 @@
package terminal;
import static com.googlecode.lanterna.input.KeyType.*;
import static terminal.ControlSequenceHandler.isEscape;
import static util.Characters.EOF;
@ -54,17 +55,17 @@ public class LispTerminal {
});
}
private void resize() {
private synchronized void resize() {
terminalSize = terminal.getTerminalSize();
}
public void run() {
public void start() {
executorService.execute(this::readInput);
executorService.execute(this::writeOutput);
executorService.shutdown();
}
public void readInput() {
private void readInput() {
while (!isFinished)
processNextKey();
}
@ -83,11 +84,10 @@ public class LispTerminal {
try {
keyStroke = terminal.pollInput();
} catch (IllegalStateException e) {
// Issue #299
} catch (IllegalStateException e) { // issue #299
moveCursorToEndOfInput();
terminal.putCharacter('\n');
terminal.close();
System.exit(0);
stop();
}
return keyStroke;
@ -108,7 +108,7 @@ public class LispTerminal {
private synchronized void doControlKey(KeyStroke keyStroke) {
KeyType keyType = keyStroke.getKeyType();
if (keyType == KeyType.Character)
if (keyType == Character)
doControlCharacter(keyStroke);
}
@ -119,99 +119,26 @@ public class LispTerminal {
private synchronized void doControlD() {
doEnter();
finish();
stop();
}
private void doNormalKey(KeyStroke keyStroke) {
private synchronized void doNormalKey(KeyStroke keyStroke) {
KeyType keyType = keyStroke.getKeyType();
if (keyType == KeyType.ArrowLeft)
moveCursorLeft();
else if (keyType == KeyType.ArrowRight)
moveCursorRight();
else if (keyType == KeyType.Enter)
if (keyType == Enter)
doEnter();
else if (keyType == KeyType.Backspace)
else if (keyType == ArrowLeft)
doLeftArrow();
else if (keyType == ArrowRight)
doRightArrow();
else if (keyType == Backspace)
doBackspace();
else if (keyType == KeyType.Delete)
else if (keyType == Delete)
doDelete();
else if (keyType == KeyType.Character)
else if (keyType == Character)
doCharacter(keyStroke.getCharacter());
}
private synchronized void moveCursorLeft() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveLeft(cursorPosition))
retractCursor(cursorPosition);
}
private synchronized boolean isPossibleToMoveLeft(TerminalPosition cursorPosition) {
return getDistanceFromOrigin(cursorPosition) > 0;
}
private synchronized int getDistanceFromOrigin(TerminalPosition cursorPosition) {
int columnDifference = cursorPosition.getColumn() - originColumn;
int rowDifference = cursorPosition.getRow() - originRow;
int totalColumns = terminalSize.getColumns();
return columnDifference + (totalColumns * rowDifference);
}
private synchronized void retractCursor(TerminalPosition cursorPosition) {
TerminalPosition newPosition = cursorPosition.withRelativeColumn(-1);
if (isAtStartOfRow(cursorPosition))
newPosition = cursorPosition.withColumn(terminalSize.getColumns()).withRelativeRow(-1);
terminal.setCursorPosition(newPosition);
}
private boolean isAtStartOfRow(TerminalPosition cursorPosition) {
return cursorPosition.getColumn() == 0;
}
private synchronized void moveCursorRight() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveRight(cursorPosition))
advanceCursor(cursorPosition);
}
private synchronized boolean isPossibleToMoveRight(TerminalPosition cursorPosition) {
return getDistanceFromOrigin(cursorPosition) < inputLine.length();
}
private synchronized void advanceCursor(TerminalPosition cursorPosition) {
if (isEndOfRow(cursorPosition))
moveCursorToNextRow(cursorPosition);
else
terminal.setCursorPosition(cursorPosition.withRelativeColumn(1));
}
private synchronized boolean isEndOfRow(TerminalPosition cursorPosition) {
return cursorPosition.getColumn() >= terminalSize.getColumns() - 1;
}
private synchronized void moveCursorToNextRow(TerminalPosition cursorPosition) {
if (isEndOfBuffer(cursorPosition))
createNewRowForCursor(cursorPosition);
else
terminal.setCursorPosition(cursorPosition.withColumn(0).withRelativeRow(1));
}
private synchronized boolean isEndOfBuffer(TerminalPosition cursorPosition) {
return cursorPosition.getRow() == terminalSize.getRows() - 1;
}
private synchronized void createNewRowForCursor(TerminalPosition cursorPosition) {
terminal.setCursorPosition(cursorPosition);
terminal.putCharacter('\n');
terminal.setCursorPosition(cursorPosition.withColumn(0));
--originRow;
}
private synchronized void doEnter() {
moveCursorToEndOfInput();
terminal.putCharacter('\n');
@ -241,71 +168,122 @@ public class LispTerminal {
originRow = cursorPosition.getRow();
}
private synchronized void doLeftArrow() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveLeft(cursorPosition))
moveCursorLeft(cursorPosition);
}
private synchronized boolean isPossibleToMoveLeft(TerminalPosition cursorPosition) {
return getDistanceFromOrigin(cursorPosition) > 0;
}
private synchronized int getDistanceFromOrigin(TerminalPosition cursorPosition) {
int columnDifference = cursorPosition.getColumn() - originColumn;
int rowDifference = cursorPosition.getRow() - originRow;
int totalColumns = terminalSize.getColumns();
return columnDifference + (totalColumns * rowDifference);
}
private synchronized void moveCursorLeft(TerminalPosition cursorPosition) {
TerminalPosition newPosition = cursorPosition.withRelativeColumn(-1);
if (isAtStartOfRow(cursorPosition))
newPosition = cursorPosition.withColumn(terminalSize.getColumns()).withRelativeRow(-1);
terminal.setCursorPosition(newPosition);
}
private synchronized boolean isAtStartOfRow(TerminalPosition cursorPosition) {
return cursorPosition.getColumn() == 0;
}
private synchronized void doRightArrow() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveRight(cursorPosition))
moveCursorRight(cursorPosition);
}
private synchronized boolean isPossibleToMoveRight(TerminalPosition cursorPosition) {
return getDistanceFromOrigin(cursorPosition) < inputLine.length();
}
private synchronized void moveCursorRight(TerminalPosition cursorPosition) {
if (isEndOfRow(cursorPosition))
moveCursorToNextRow(cursorPosition);
else
terminal.setCursorPosition(cursorPosition.withRelativeColumn(1));
}
private synchronized boolean isEndOfRow(TerminalPosition cursorPosition) {
return cursorPosition.getColumn() >= terminalSize.getColumns() - 1;
}
private synchronized void moveCursorToNextRow(TerminalPosition cursorPosition) {
if (isEndOfBuffer(cursorPosition))
createNewRowForCursor(cursorPosition);
else
terminal.setCursorPosition(cursorPosition.withColumn(0).withRelativeRow(1));
}
private synchronized boolean isEndOfBuffer(TerminalPosition cursorPosition) {
return cursorPosition.getRow() == terminalSize.getRows() - 1;
}
private synchronized void createNewRowForCursor(TerminalPosition cursorPosition) {
terminal.setCursorPosition(cursorPosition);
terminal.putCharacter('\n');
terminal.setCursorPosition(cursorPosition.withColumn(0));
--originRow;
}
private synchronized void doBackspace() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveLeft(cursorPosition)) {
String remaining = inputLine.substring(getDistanceFromOrigin(cursorPosition), inputLine.length());
inputLine = inputLine.substring(0, getDistanceFromOrigin(cursorPosition) - 1) + remaining;
if (isPossibleToMoveLeft(cursorPosition))
deletePreviousCharacter(cursorPosition);
}
retractCursor(cursorPosition);
private synchronized void deletePreviousCharacter(TerminalPosition cursorPosition) {
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
String remaining = inputLine.substring(distanceFromOrigin, inputLine.length());
inputLine = inputLine.substring(0, distanceFromOrigin - 1) + remaining;
moveCursorLeft(cursorPosition);
putString(remaining + " ");
moveCursorLeft(cursorPosition);
}
for (char c : remaining.toCharArray())
terminal.putCharacter(c);
terminal.putCharacter(' ');
retractCursor(cursorPosition);
}
private synchronized void putString(String characters) {
for (char c : characters.toCharArray())
terminal.putCharacter(c);
}
private synchronized void doDelete() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveRight(cursorPosition)) {
String remaining = inputLine.substring(getDistanceFromOrigin(cursorPosition) + 1, inputLine.length());
inputLine = inputLine.substring(0, getDistanceFromOrigin(cursorPosition)) + remaining;
if (isPossibleToMoveRight(cursorPosition))
deleteCharacterAtPosition(cursorPosition);
}
for (char c : remaining.toCharArray())
terminal.putCharacter(c);
terminal.putCharacter(' ');
terminal.setCursorPosition(cursorPosition);
}
private synchronized void deleteCharacterAtPosition(TerminalPosition cursorPosition) {
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
String remaining = inputLine.substring(distanceFromOrigin + 1, inputLine.length());
inputLine = inputLine.substring(0, distanceFromOrigin) + remaining;
putString(remaining + " ");
terminal.setCursorPosition(cursorPosition);
}
private synchronized void doCharacter(Character character) {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isPossibleToMoveRight(cursorPosition))
insertCharacter(character, cursorPosition);
else
appendCharacter(character, cursorPosition);
}
private synchronized void insertCharacter(Character character, TerminalPosition cursorPosition) {
if (!isBufferFilled()) {
int oldOriginRow = originRow;
advanceCursor(getLeadingEdge());
if (originRow != oldOriginRow) {
terminal.setCursorPosition(new TerminalPosition(originColumn, originRow));
for (char c : inputLine.toCharArray())
terminal.putCharacter(c);
cursorPosition = cursorPosition.withRelativeRow(-1);
}
terminal.setCursorPosition(cursorPosition);
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
String remaining = character + inputLine.substring(distanceFromOrigin, inputLine.length());
inputLine = inputLine.substring(0, distanceFromOrigin) + remaining;
for (char c : remaining.toCharArray())
terminal.putCharacter(c);
advanceCursor(cursorPosition);
}
if (!isBufferFilled())
if (isPossibleToMoveRight(cursorPosition))
insertCharacter(character, cursorPosition);
else
appendCharacter(character, cursorPosition);
}
private synchronized boolean isBufferFilled() {
@ -315,10 +293,38 @@ public class LispTerminal {
return (row == terminalSize.getRows() - 1) && (column >= terminalSize.getColumns() - 1) && (originRow <= 0);
}
private synchronized void insertCharacter(Character character, TerminalPosition cursorPosition) {
cursorPosition = shiftPositionIfNewRowAdded(cursorPosition);
terminal.setCursorPosition(cursorPosition);
int distanceFromOrigin = getDistanceFromOrigin(cursorPosition);
String remaining = character + inputLine.substring(distanceFromOrigin, inputLine.length());
inputLine = inputLine.substring(0, distanceFromOrigin) + remaining;
putString(remaining);
moveCursorRight(cursorPosition);
}
private synchronized TerminalPosition shiftPositionIfNewRowAdded(TerminalPosition cursorPosition) {
int oldOriginRow = originRow;
moveCursorRight(getLeadingEdge());
return isNewRowAdded(oldOriginRow) ? adjustCursorPosition(cursorPosition) : cursorPosition;
}
private synchronized boolean isNewRowAdded(int oldOriginRow) {
return originRow != oldOriginRow;
}
private synchronized TerminalPosition adjustCursorPosition(TerminalPosition cursorPosition) {
terminal.setCursorPosition(new TerminalPosition(originColumn, originRow));
putString(inputLine);
return cursorPosition.withRelativeRow(-1);
}
private synchronized void appendCharacter(Character character, TerminalPosition cursorPosition) {
terminal.putCharacter(character);
inputLine += character;
advanceCursor(cursorPosition);
moveCursorRight(cursorPosition);
}
private void takeNap() {
@ -329,7 +335,7 @@ public class LispTerminal {
}
}
public void writeOutput() {
private void writeOutput() {
for (int c = outputReader.read(); c != EOF; c = outputReader.read())
processOutput((char) c);
@ -342,7 +348,7 @@ public class LispTerminal {
if (isEscape(c))
parseControlSequence();
else if (isEndOfSegment(c))
printSegment();
writeSegment();
else
outputSegment += c;
}
@ -353,7 +359,7 @@ public class LispTerminal {
return c == END_OF_SEGMENT;
}
private synchronized void printSegment() {
private synchronized void writeSegment() {
terminal.setCursorVisible(false);
printSegmentCharacters();
terminal.setCursorVisible(true);
@ -363,10 +369,7 @@ public class LispTerminal {
private synchronized void printSegmentCharacters() {
moveCursorToEndOfInput();
for (char c : outputSegment.toCharArray())
terminal.putCharacter(c);
putString(outputSegment);
moveCursorToNextRowIfNecessary();
terminal.flush();
}
@ -378,7 +381,7 @@ public class LispTerminal {
moveCursorToNextRow(cursorPosition);
}
public void finish() {
public void stop() {
isFinished = true;
inputWriter.close();
}

View File

@ -135,12 +135,12 @@ public class LispTerminalTest {
flushListener = new FlushListener();
virtualTerminal.addVirtualTerminalListener(flushListener);
lispTerminal = new LispTerminal(virtualTerminal, inputWriter, outputReader);
lispTerminal.run();
lispTerminal.start();
}
@After
public void tearDown() throws IOException {
lispTerminal.finish();
lispTerminal.stop();
outputWriter.close();
}
@ -425,6 +425,15 @@ public class LispTerminalTest {
assertCharacterPositions(new char[][] { { '0', '0', '0' }, { '1', '1', '1' }, { '2', '2', ' ' } });
}
@Test
public void appendingTextDoesNothingWhenBufferFilled() {
setColumns(3);
setRows(3);
enterCharacters("000111222333444");
assertCursorPosition(2, 2);
assertCharacterPositions(new char[][] { { '0', '0', '0' }, { '1', '1', '1' }, { '2', '2', ' ' } });
}
@Test
public void printedOutputToEndOfRow_MovesCursorToNextRow() {
setColumns(3);