From 2ba264bc29a91db81dc19daba9a82eae9495f857 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Sat, 21 May 2016 10:05:28 -0700 Subject: [PATCH] Add history to REPL. --- src/module/repl.wren | 50 ++++++++++++++++++++++-------- src/module/repl.wren.inc | 66 +++++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/module/repl.wren b/src/module/repl.wren index 23089d21..105e53dc 100644 --- a/src/module/repl.wren +++ b/src/module/repl.wren @@ -12,6 +12,9 @@ class Repl { construct new() { _cursor = 0 _line = "" + + _history = [] + _historyIndex = 0 } run() { @@ -27,7 +30,7 @@ class Repl { return } else if (byte == Chars.ctrlD) { // If the line is empty, Ctrl_D exits. - if (_line == "") { + if (!_line.isEmpty) { System.print() return } @@ -83,11 +86,9 @@ class Repl { if (escapeType == Chars.leftBracket) { // ESC [ sequence. if (value == EscapeBracket.up) { - // TODO: Handle this. - System.print("up") + previousHistory() } else if (value == EscapeBracket.down) { - // TODO: Handle this. - System.print("down") + nextHistory() } else if (value == EscapeBracket.left) { // Move the cursor left one. if (_cursor > 0) _cursor = _cursor - 1 @@ -101,22 +102,46 @@ class Repl { } } + previousHistory() { + if (_historyIndex == 0) return + + _historyIndex = _historyIndex - 1 + _line = _history[_historyIndex] + _cursor = _line.count + } + + nextHistory() { + if (_historyIndex >= _history.count) return + + _historyIndex = _historyIndex + 1 + if (_historyIndex < _history.count) { + _line = _history[_historyIndex] + _cursor = _line.count + } else { + _line = "" + _cursor = 0 + } + } + executeInput() { - System.print() + // Add it to the history. + _history.add(_line) + _historyIndex = _history.count + + // Reset the current line. var input = _line _line = "" _cursor = 0 + System.print() + // Guess if it looks like a statement or expression. Statements need to be // evaluated at the top level in case they declare variables, but they // don't return a value. Expressions need to have their result displayed. var tokens = lex(input, false) - if (tokens.isEmpty) { - // No code, so do nothing. - // TODO: Temp. - System.print("empty") - return - } + + // No code, so do nothing. + if (tokens.isEmpty) return var first = tokens[0] var isStatement = @@ -148,6 +173,7 @@ class Repl { // TODO: Handle error in result.toString. System.print("%(Color.brightWhite)%(result)%(Color.none)") return + } } System.print("%(Color.red)Runtime error: %(result)%(Color.none)") diff --git a/src/module/repl.wren.inc b/src/module/repl.wren.inc index 0afc3f35..c19ddbae 100644 --- a/src/module/repl.wren.inc +++ b/src/module/repl.wren.inc @@ -14,6 +14,9 @@ static const char* replModuleSource = " construct new() {\n" " _cursor = 0\n" " _line = \"\"\n" +"\n" +" _history = []\n" +" _historyIndex = 0\n" " }\n" "\n" " run() {\n" @@ -29,7 +32,7 @@ static const char* replModuleSource = " return\n" " } else if (byte == Chars.ctrlD) {\n" " // If the line is empty, Ctrl_D exits.\n" -" if (_line == \"\") {\n" +" if (!_line.isEmpty) {\n" " System.print()\n" " return\n" " }\n" @@ -85,11 +88,9 @@ static const char* replModuleSource = " if (escapeType == Chars.leftBracket) {\n" " // ESC [ sequence.\n" " if (value == EscapeBracket.up) {\n" -" // TODO: Handle this.\n" -" System.print(\"up\")\n" +" previousHistory()\n" " } else if (value == EscapeBracket.down) {\n" -" // TODO: Handle this.\n" -" System.print(\"down\")\n" +" nextHistory()\n" " } else if (value == EscapeBracket.left) {\n" " // Move the cursor left one.\n" " if (_cursor > 0) _cursor = _cursor - 1\n" @@ -103,22 +104,46 @@ static const char* replModuleSource = " }\n" " }\n" "\n" +" previousHistory() {\n" +" if (_historyIndex == 0) return\n" +"\n" +" _historyIndex = _historyIndex - 1\n" +" _line = _history[_historyIndex]\n" +" _cursor = _line.count\n" +" }\n" +"\n" +" nextHistory() {\n" +" if (_historyIndex >= _history.count) return\n" +"\n" +" _historyIndex = _historyIndex + 1\n" +" if (_historyIndex < _history.count) {\n" +" _line = _history[_historyIndex]\n" +" _cursor = _line.count\n" +" } else {\n" +" _line = \"\"\n" +" _cursor = 0\n" +" }\n" +" }\n" +"\n" " executeInput() {\n" -" System.print()\n" +" // Add it to the history.\n" +" _history.add(_line)\n" +" _historyIndex = _history.count\n" +"\n" +" // Reset the current line.\n" " var input = _line\n" " _line = \"\"\n" " _cursor = 0\n" "\n" +" System.print()\n" +"\n" " // Guess if it looks like a statement or expression. Statements need to be\n" " // evaluated at the top level in case they declare variables, but they\n" " // don't return a value. Expressions need to have their result displayed.\n" " var tokens = lex(input, false)\n" -" if (tokens.isEmpty) {\n" -" // No code, so do nothing.\n" -" // TODO: Temp.\n" -" System.print(\"empty\")\n" -" return\n" -" }\n" +"\n" +" // No code, so do nothing.\n" +" if (tokens.isEmpty) return\n" "\n" " var first = tokens[0]\n" " var isStatement =\n" @@ -132,30 +157,29 @@ static const char* replModuleSource = " first.type == Token.varKeyword ||\n" " first.type == Token.whileKeyword\n" "\n" +" var fiber\n" " if (isStatement) {\n" -" var fiber = Fiber.new {\n" +" fiber = Fiber.new {\n" " Meta.eval(input)\n" " }\n" "\n" " var result = fiber.try()\n" -" if (fiber.error != null) {\n" -" System.print(\"%(Color.red)Runtime error: %(result)%(Color.none)\")\n" -" // TODO: Print entire stack.\n" -" }\n" +" if (fiber.error == null) return\n" " } else {\n" " var function = Meta.compileExpression(input)\n" " if (function == null) return\n" "\n" -" var fiber = Fiber.new(function)\n" +" fiber = Fiber.new(function)\n" " var result = fiber.try()\n" " if (fiber.error == null) {\n" " // TODO: Handle error in result.toString.\n" " System.print(\"%(Color.brightWhite)%(result)%(Color.none)\")\n" -" } else {\n" -" System.print(\"%(Color.red)Runtime error: %(result)%(Color.none)\")\n" -" // TODO: Print entire stack.\n" +" return\n" " }\n" " }\n" +"\n" +" System.print(\"%(Color.red)Runtime error: %(result)%(Color.none)\")\n" +" // TODO: Print entire stack.\n" " }\n" "\n" " lex(line, includeWhitespace) {\n"