Clean up terminal code
This commit is contained in:
parent
fc96894d14
commit
a8eff1ad70
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue