diff --git a/src/terminal/ControlSequenceHandler.java b/src/terminal/ControlSequenceHandler.java index 8fd5aea..b5ff655 100644 --- a/src/terminal/ControlSequenceHandler.java +++ b/src/terminal/ControlSequenceHandler.java @@ -8,10 +8,8 @@ import stream.SafeInputStream; class ControlSequenceHandler { - private static final char ESCAPE = '\u001B'; - public static final boolean isEscape(char c) { - return c == ESCAPE; + return c == UNICODE_ESCAPE; } private SafeInputStream input; diff --git a/src/terminal/ControlSequenceLookup.java b/src/terminal/ControlSequenceLookup.java index 98fdf7b..febb75a 100644 --- a/src/terminal/ControlSequenceLookup.java +++ b/src/terminal/ControlSequenceLookup.java @@ -8,21 +8,21 @@ import terminal.ControlSequence.NullControlSequence; public class ControlSequenceLookup { - private static Map> controlSequenceMap = new HashMap<>(); + private static Map> commands = new HashMap<>(); static { - Map selectGraphicRenditionMap = new HashMap<>(); + Map sgrCodes = new HashMap<>(); for (SelectGraphicRendition sgr : SelectGraphicRendition.values()) - selectGraphicRenditionMap.put(sgr.getCode(), sgr); + sgrCodes.put(sgr.getCode(), sgr); - controlSequenceMap.put(SGR_COMMAND, selectGraphicRenditionMap); + commands.put(SGR_COMMAND, sgrCodes); } public static ControlSequence lookupControlSequence(char command, String code) { - Map commandMap = controlSequenceMap.getOrDefault(command, new HashMap<>()); + Map codes = commands.getOrDefault(command, new HashMap<>()); - return commandMap.getOrDefault(code, new NullControlSequence()); + return codes.getOrDefault(code, new NullControlSequence()); } } \ No newline at end of file diff --git a/src/terminal/LispTerminal.java b/src/terminal/LispTerminal.java index ca195ff..94ac42a 100644 --- a/src/terminal/LispTerminal.java +++ b/src/terminal/LispTerminal.java @@ -3,6 +3,7 @@ package terminal; import static com.googlecode.lanterna.input.KeyType.*; import static terminal.ControlSequenceHandler.isEscape; import static util.Characters.EOF; +import static util.Characters.UNICODE_NULL; import java.io.*; import java.util.concurrent.*; @@ -15,7 +16,7 @@ import stream.*; public class LispTerminal { - public static final char END_OF_SEGMENT = 'x'; + public static final char END_OF_SEGMENT = UNICODE_NULL; private IOSafeTerminal terminal; private SafeOutputStream inputWriter; @@ -54,6 +55,10 @@ public class LispTerminal { terminalSize = terminal.getTerminalSize(); terminal.clearScreen(); terminal.setCursorPosition(0, 0); + redisplayInput(); + } + + private synchronized void redisplayInput() { setOriginToCurrentPosition(); putStringToTerminal(inputLine); moveCursorToEndOfInput(); @@ -358,14 +363,14 @@ public class LispTerminal { printSegmentCharacters(); terminal.setCursorVisible(true); outputSegment = ""; - setOriginToCurrentPosition(); + redisplayInput(); + terminal.flush(); } private synchronized void printSegmentCharacters() { moveCursorToEndOfInput(); putOutputToTerminal(); moveCursorToNextRowIfNecessary(); - terminal.flush(); } private synchronized void putOutputToTerminal() { diff --git a/src/util/Characters.java b/src/util/Characters.java index fd2092e..1840bb8 100644 --- a/src/util/Characters.java +++ b/src/util/Characters.java @@ -24,6 +24,8 @@ public final class Characters { public static final char RIGHT_SQUARE_BRACKET = ']'; public static final char SEMICOLON = ';'; public static final char SINGLE_QUOTE = '\''; + public static final char UNICODE_ESCAPE = '\u001B'; + public static final char UNICODE_NULL = '\u0000'; public static final Set illegalIdentifierCharacters = new HashSet<>(); diff --git a/test/terminal/LispTerminalTest.java b/test/terminal/LispTerminalTest.java index 9b5aefb..1cb05bc 100644 --- a/test/terminal/LispTerminalTest.java +++ b/test/terminal/LispTerminalTest.java @@ -452,18 +452,52 @@ public class LispTerminalTest { } @Test - public void printedOutputDoesNotOverwriteInput() { + public void outputDoesNotOverwriteInput_AndRedisplaysInput() { setColumns(3); - enterCharacters("01201201"); - pressKeyTimes(ArrowLeft, 5); + enterCharacters("0123"); + pressKeyTimes(ArrowLeft, 3); produceOutput("out"); - assertCursorPosition(0, 4); - assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', 'o' }, - { 'u', 't', ' ' } }); + assertCursorPosition(2, 3); + assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '3', 'o', 'u' }, { 't', '0', '1' }, + { '2', '3', ' ' }, { ' ', ' ', ' ' } }); } @Test - public void printedOutputDoesNotOverwriteInput_AfterEnter() { + public void outputEndsOnSecondToLastColumn_MovesToNewRow() { + setColumns(3); + enterCharacters("01234"); + pressKeyTimes(ArrowLeft, 3); + produceOutput("out"); + assertCursorPosition(2, 4); + assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '3', '4', 'o' }, { 'u', 't', ' ' }, + { '0', '1', '2' }, { '3', '4', ' ' } }); + } + + @Test + public void outputEndsOnLastColumn_MovesToNewRow() { + setColumns(3); + enterCharacters("012345"); + pressKeyTimes(ArrowLeft, 3); + produceOutput("out"); + assertCursorPosition(0, 5); + assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '3', '4', '5' }, { 'o', 'u', 't' }, + { '0', '1', '2' }, { '3', '4', '5' }, { ' ', ' ', ' ' } }); + } + + @Test + public void outputRedisplaysInputAtEndOfBuffer() { + setColumns(3); + setRows(4); + enterCharacters("01234"); + pressKeyTimes(ArrowLeft, 3); + produceOutput("out"); + assertCursorPosition(2, 3); + assertCharacterPositions(new char[][] { { '3', '4', 'o' }, { 'u', 't', ' ' }, { '0', '1', '2' }, + { '3', '4', ' ' } }); + } + + @Test + public void outputDoesNotOverwriteInput_AfterEnter() { setColumns(3); enterCharacters("01201201"); pressKeyTimes(ArrowLeft, 5); @@ -471,7 +505,7 @@ public class LispTerminalTest { produceOutput("out"); assertCursorPosition(0, 4); assertCharacterPositions(new char[][] { { '0', '1', '2' }, { '0', '1', '2' }, { '0', '1', ' ' }, - { 'o', 'u', 't' } }); + { 'o', 'u', 't' }, { ' ', ' ', ' ' } }); } @Test @@ -509,7 +543,7 @@ public class LispTerminalTest { } @Test - public void controlSequenceIsNotPrinted() { + public void controlSequencesAreNotPrinted() { produceOutput("\u001B[32mcontrol\u001B[0mseq"); assertCharacterPositions(new char[][] { { 'c', 'o', 'n', 't', 'r', 'o', 'l', 's', 'e', 'q' } }); }