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:
parent
38ab1144fb
commit
ad173d06a9
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue