diff --git a/src/main/LispMain.java b/src/main/LispMain.java index e3ebaf8..e1abdd7 100644 --- a/src/main/LispMain.java +++ b/src/main/LispMain.java @@ -3,6 +3,7 @@ package main; import java.util.function.Function; import interpreter.*; +import terminal.LispTerminal; public class LispMain { @@ -15,8 +16,12 @@ public class LispMain { private LispMain() {} public static void main(String[] args) { - LispInterpreter interpreter = buildInterpreter(args); - interpreter.interpret(); + LispTerminal terminal = new LispTerminal(); + + terminal.run(); + + // LispInterpreter interpreter = buildInterpreter(args); + // interpreter.interpret(); } private static LispInterpreter buildInterpreter(String[] args) { diff --git a/src/terminal/LispTerminal.java b/src/terminal/LispTerminal.java new file mode 100644 index 0000000..7471b14 --- /dev/null +++ b/src/terminal/LispTerminal.java @@ -0,0 +1,137 @@ +package terminal; + +import java.io.IOException; + +import com.googlecode.lanterna.TerminalPosition; +import com.googlecode.lanterna.input.*; +import com.googlecode.lanterna.terminal.*; + +public class LispTerminal implements Runnable { + + private IOSafeTerminal terminal; + private boolean isFinished; + private String currentLine; + + public LispTerminal() { + try { + Terminal unsafe = new DefaultTerminalFactory().createTerminal(); + this.terminal = IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter(unsafe); + } catch (IOException e) { + // TODO + e.printStackTrace(); + } + + this.isFinished = false; + this.currentLine = ""; + } + + public void run() { + while (!isFinished) { + handleKeyStroke(getKeyStroke()); + terminal.flush(); + } + + terminal.close(); + } + + private KeyStroke getKeyStroke() { + KeyStroke keyStroke = null; + + try { + keyStroke = terminal.readInput(); + } catch (IllegalStateException e) { + // TODO - lantera is trying to exit private mode on ctrl-c (which we didn't enter) + terminal.putCharacter('`'); + isFinished = true; + } + + return keyStroke; + } + + private void handleKeyStroke(KeyStroke keyStroke) { + if (keyStroke == null) + return; + + KeyType keyType = keyStroke.getKeyType(); + + if (keyType == KeyType.ArrowLeft) + moveCursorLeft(); + else if (keyType == KeyType.ArrowRight) + moveCursorRight(); + else if (keyType == KeyType.Enter) + doEnter(); + else if (keyType == KeyType.Backspace) + doBackspace(); + else if (keyType == KeyType.Delete) + doDelete(); + else if (keyType == KeyType.Character) + doCharacter(keyStroke); + } + + private void doEnter() { + terminal.putCharacter('\n'); + currentLine = ""; + } + + private void moveCursorLeft() { + TerminalPosition cursorPosition = terminal.getCursorPosition(); + terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1)); + } + + private void moveCursorRight() { + TerminalPosition cursorPosition = terminal.getCursorPosition(); + + if (cursorPosition.getColumn() < currentLine.length()) + terminal.setCursorPosition(cursorPosition.withRelativeColumn(1)); + } + + private void doBackspace() { + TerminalPosition cursorPosition = terminal.getCursorPosition(); + + if (cursorPosition.getColumn() > 0) { + String remaining = currentLine.substring(cursorPosition.getColumn(), currentLine.length()); + currentLine = currentLine.substring(0, cursorPosition.getColumn() - 1) + remaining; + terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1)); + + for (char c : remaining.toCharArray()) + terminal.putCharacter(c); + + terminal.putCharacter(' '); + terminal.setCursorPosition(cursorPosition.withRelativeColumn(-1)); + } + } + + private void doDelete() { + TerminalPosition cursorPosition = terminal.getCursorPosition(); + + if (cursorPosition.getColumn() < currentLine.length()) { + String remaining = currentLine.substring(cursorPosition.getColumn() + 1, currentLine.length()); + currentLine = currentLine.substring(0, cursorPosition.getColumn()) + remaining; + + for (char c : remaining.toCharArray()) + terminal.putCharacter(c); + + terminal.putCharacter(' '); + terminal.setCursorPosition(cursorPosition); + } + } + + private void doCharacter(KeyStroke keyStroke) { + TerminalPosition cursorPosition = terminal.getCursorPosition(); + + if (cursorPosition.getColumn() < currentLine.length()) { + String remaining = keyStroke.getCharacter() + + currentLine.substring(cursorPosition.getColumn(), currentLine.length()); + currentLine = currentLine.substring(0, cursorPosition.getColumn()) + remaining; + + for (char c : remaining.toCharArray()) + terminal.putCharacter(c); + + terminal.setCursorPosition(cursorPosition.withRelativeColumn(1)); + } else { + terminal.putCharacter(keyStroke.getCharacter()); + currentLine += keyStroke.getCharacter(); + } + } + +}