Fix issues when input pushes past end of buffer

A few issues still remain:

- Inserting text pushes the remainder of the input to a new line
  at the end of the buffer.

- Resizing the terminal height causes numerous issues.
This commit is contained in:
Mike Cifelli 2017-03-19 17:17:34 -04:00
parent 38ab1144fb
commit ad173d06a9
3 changed files with 167 additions and 12 deletions

View File

@ -76,10 +76,10 @@ public class LispMain {
builder.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE)); builder.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE));
} else { } else {
builder.setOutputDecorator(makeInteractiveDecorator(ANSI_GREEN)); builder.setOutputDecorator(makeInteractiveDecorator(ANSI_GREEN));
builder.setValueOutputDecorator(makeInteractiveDecorator(ANSI_GREEN)); builder.setValueOutputDecorator(s -> s);
builder.setWarningOutputDecorator(makeInteractiveDecorator(ANSI_YELLOW)); builder.setWarningOutputDecorator(s -> s);
builder.setErrorOutputDecorator(makeInteractiveDecorator(ANSI_RED)); builder.setErrorOutputDecorator(s -> s);
builder.setCriticalOutputDecorator(makeInteractiveDecorator(ANSI_PURPLE)); builder.setCriticalOutputDecorator(s -> s);
} }
} }

View File

@ -20,6 +20,7 @@ public class LispTerminal {
private ExecutorService executorService; private ExecutorService executorService;
private ControlSequenceHandler controlSequenceHandler; private ControlSequenceHandler controlSequenceHandler;
private TerminalPosition origin; private TerminalPosition origin;
private TerminalPosition leadingEdge;
private String inputLine; private String inputLine;
private String outputSegment; private String outputSegment;
private boolean isFinished; private boolean isFinished;
@ -31,6 +32,7 @@ public class LispTerminal {
this.executorService = Executors.newFixedThreadPool(2); this.executorService = Executors.newFixedThreadPool(2);
this.controlSequenceHandler = new ControlSequenceHandler(); this.controlSequenceHandler = new ControlSequenceHandler();
this.origin = terminal.getCursorPosition(); this.origin = terminal.getCursorPosition();
this.leadingEdge = origin;
this.inputLine = ""; this.inputLine = "";
this.outputSegment = ""; this.outputSegment = "";
this.isFinished = false; this.isFinished = false;
@ -130,10 +132,15 @@ public class LispTerminal {
} }
private synchronized void retractCursor(TerminalPosition cursorPosition) { private synchronized void retractCursor(TerminalPosition cursorPosition) {
TerminalPosition newPosition = cursorPosition.withRelativeColumn(-1);
if (isAtStartOfRow(cursorPosition)) if (isAtStartOfRow(cursorPosition))
terminal.setCursorPosition(terminal.getTerminalSize().getColumns(), cursorPosition.getRow() - 1); newPosition = cursorPosition.withColumn(terminal.getTerminalSize().getColumns()).withRelativeRow(-1);
else
terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1)); terminal.setCursorPosition(newPosition);
if (distanceFromOrigin(newPosition) == inputLine.length())
leadingEdge = terminal.getCursorPosition();
} }
private boolean isAtStartOfRow(TerminalPosition cursorPosition) { private boolean isAtStartOfRow(TerminalPosition cursorPosition) {
@ -153,16 +160,40 @@ public class LispTerminal {
private synchronized void advanceCursor(TerminalPosition cursorPosition) { private synchronized void advanceCursor(TerminalPosition cursorPosition) {
if (isAtEndOfRow(cursorPosition)) if (isAtEndOfRow(cursorPosition))
terminal.setCursorPosition(0, cursorPosition.getRow() + 1); moveCursorToNextRow(cursorPosition);
else else
terminal.setCursorPosition(cursorPosition.withRelativeColumn(1)); terminal.setCursorPosition(cursorPosition.withRelativeColumn(1));
TerminalPosition newPosition = terminal.getCursorPosition();
if (distanceFromOrigin(newPosition) == inputLine.length())
leadingEdge = terminal.getCursorPosition();
} }
private synchronized boolean isAtEndOfRow(TerminalPosition cursorPosition) { private synchronized boolean isAtEndOfRow(TerminalPosition cursorPosition) {
return cursorPosition.getColumn() == terminal.getTerminalSize().getColumns() - 1; return cursorPosition.getColumn() >= terminal.getTerminalSize().getColumns() - 1;
}
private void moveCursorToNextRow(TerminalPosition cursorPosition) {
if (isEndOfBuffer())
createNewRowForCursor();
else
terminal.setCursorPosition(cursorPosition.withColumn(0).withRelativeRow(1));
}
private boolean isEndOfBuffer() {
return terminal.getCursorPosition().getRow() == terminal.getTerminalSize().getRows() - 1;
}
private void createNewRowForCursor() {
TerminalPosition originalPosition = terminal.getCursorPosition();
terminal.putCharacter('\n');
terminal.setCursorPosition(originalPosition.withColumn(0));
origin = origin.withRelativeRow(-1);
} }
private synchronized void doEnter() { private synchronized void doEnter() {
moveCursorToEndOfInput();
terminal.putCharacter('\n'); terminal.putCharacter('\n');
inputLine += "\n"; inputLine += "\n";
@ -176,6 +207,7 @@ public class LispTerminal {
inputLine = ""; inputLine = "";
origin = terminal.getCursorPosition(); origin = terminal.getCursorPosition();
leadingEdge = origin;
} }
private synchronized void doBackspace() { private synchronized void doBackspace() {
@ -270,14 +302,28 @@ public class LispTerminal {
private synchronized void printSegment() { private synchronized void printSegment() {
terminal.setCursorVisible(false); terminal.setCursorVisible(false);
moveCursorToEndOfInput();
for (char c : outputSegment.toCharArray()) for (char c : outputSegment.toCharArray())
terminal.putCharacter(c); terminal.putCharacter(c);
moveCursorToNextRowIfNecessary();
terminal.flush(); terminal.flush();
terminal.setCursorVisible(true); terminal.setCursorVisible(true);
outputSegment = ""; outputSegment = "";
origin = terminal.getCursorPosition(); origin = terminal.getCursorPosition();
leadingEdge = origin;
}
private synchronized void moveCursorToEndOfInput() {
terminal.setCursorPosition(leadingEdge);
}
private synchronized void moveCursorToNextRowIfNecessary() {
TerminalPosition cursorPosition = terminal.getCursorPosition();
if (isAtEndOfRow(cursorPosition))
moveCursorToNextRow(cursorPosition);
} }
public void finish() { public void finish() {

View File

@ -74,14 +74,18 @@ public class LispTerminalTest {
virtualTerminal.setTerminalSize(new TerminalSize(columns, virtualTerminal.getTerminalSize().getRows())); virtualTerminal.setTerminalSize(new TerminalSize(columns, virtualTerminal.getTerminalSize().getRows()));
} }
private void setRows(int rows) {
virtualTerminal.setTerminalSize(new TerminalSize(virtualTerminal.getTerminalSize().getColumns(), rows));
}
private void assertCursorPosition(int column, int row) { private void assertCursorPosition(int column, int row) {
assertEquals(column, virtualTerminal.getCursorBufferPosition().getColumn()); assertEquals(column, virtualTerminal.getCursorPosition().getColumn());
assertEquals(row, virtualTerminal.getCursorBufferPosition().getRow()); assertEquals(row, virtualTerminal.getCursorPosition().getRow());
} }
private void assertCharacterAtPosition(char character, int column, int row) { private void assertCharacterAtPosition(char character, int column, int row) {
TerminalPosition position = new TerminalPosition(column, row); TerminalPosition position = new TerminalPosition(column, row);
assertEquals(character, virtualTerminal.getBufferCharacter(position).getCharacter()); assertEquals(character, virtualTerminal.getCharacter(position).getCharacter());
} }
private void assertInputWritten(String expected) { private void assertInputWritten(String expected) {
@ -387,6 +391,7 @@ public class LispTerminalTest {
@Test @Test
public void outputIsWritten() { public void outputIsWritten() {
produceOutput("output"); produceOutput("output");
assertCursorPosition(6, 0);
assertCharacterAtPosition('o', 0, 0); assertCharacterAtPosition('o', 0, 0);
assertCharacterAtPosition('u', 1, 0); assertCharacterAtPosition('u', 1, 0);
assertCharacterAtPosition('t', 2, 0); assertCharacterAtPosition('t', 2, 0);
@ -404,4 +409,108 @@ public class LispTerminalTest {
assertCharacterAtPosition(' ', 2, 0); assertCharacterAtPosition(' ', 2, 0);
} }
@Test
public void enterTextPastLastLineOfBuffer() {
setColumns(3);
setRows(2);
enterCharacters("01201201");
assertCursorPosition(2, 1);
assertCharacterAtPosition('0', 0, 0);
assertCharacterAtPosition('1', 1, 0);
assertCharacterAtPosition('2', 2, 0);
assertCharacterAtPosition('0', 0, 1);
assertCharacterAtPosition('1', 1, 1);
}
// @Test
// public void insertingTextPushesInputPastEndOfBuffer() {
// setColumns(2);
// setRows(3);
// enterCharacters("00112");
//
// pressKey(KeyType.ArrowLeft);
// pressKey(KeyType.ArrowLeft);
// pressKey(KeyType.ArrowLeft);
// enterCharacters("zz");
// assertCursorPosition(0, 1);
// assertCharacterAtPosition('z', 0, 0);
// assertCharacterAtPosition('z', 1, 0);
// assertCharacterAtPosition('1', 0, 1);
// assertCharacterAtPosition('1', 1, 1);
// assertCharacterAtPosition('2', 0, 2);
// }
@Test
public void printedOutputToEndOfRow_MovesCursorToNextRow() {
setColumns(3);
produceOutput("out");
assertCursorPosition(0, 1);
}
@Test
public void printedOutputToEndOfBuffer_MovesCursorToNewRow() {
setColumns(3);
setRows(2);
produceOutput("output");
assertCursorPosition(0, 1);
assertCharacterAtPosition('p', 0, 0);
assertCharacterAtPosition('u', 1, 0);
assertCharacterAtPosition('t', 2, 0);
assertCharacterAtPosition(' ', 0, 1);
assertCharacterAtPosition(' ', 1, 1);
assertCharacterAtPosition(' ', 2, 1);
}
@Test
public void printedOutputDoesNotOverwriteInput() {
setColumns(3);
enterCharacters("01201201");
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
produceOutput("out");
assertCursorPosition(0, 4);
assertCharacterAtPosition('0', 0, 0);
assertCharacterAtPosition('1', 1, 0);
assertCharacterAtPosition('2', 2, 0);
assertCharacterAtPosition('0', 0, 1);
assertCharacterAtPosition('1', 1, 1);
assertCharacterAtPosition('2', 2, 1);
assertCharacterAtPosition('0', 0, 2);
assertCharacterAtPosition('1', 1, 2);
assertCharacterAtPosition('o', 2, 2);
assertCharacterAtPosition('u', 0, 3);
assertCharacterAtPosition('t', 1, 3);
assertCharacterAtPosition(' ', 2, 3);
}
@Test
public void printedOutputDoesNotOverwriteInput_AfterEnter() {
setColumns(3);
enterCharacters("01201201");
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.ArrowLeft);
pressKey(KeyType.Enter);
produceOutput("out");
assertCursorPosition(0, 4);
assertCharacterAtPosition('0', 0, 0);
assertCharacterAtPosition('1', 1, 0);
assertCharacterAtPosition('2', 2, 0);
assertCharacterAtPosition('0', 0, 1);
assertCharacterAtPosition('1', 1, 1);
assertCharacterAtPosition('2', 2, 1);
assertCharacterAtPosition('0', 0, 2);
assertCharacterAtPosition('1', 1, 2);
assertCharacterAtPosition(' ', 2, 2);
assertCharacterAtPosition('o', 0, 3);
assertCharacterAtPosition('u', 1, 3);
assertCharacterAtPosition('t', 2, 3);
}
} }