aboutsummaryrefslogtreecommitdiff
path: root/src/ui/terminal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/terminal.cc')
-rw-r--r--src/ui/terminal.cc184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/ui/terminal.cc b/src/ui/terminal.cc
new file mode 100644
index 0000000..ccb9c4d
--- /dev/null
+++ b/src/ui/terminal.cc
@@ -0,0 +1,184 @@
+// Copyright 2021 Benjamin Barenblat
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "src/ui/terminal.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/builtin.h"
+#include "src/error.h"
+#include "src/language.h"
+#include "src/parser_driver.h"
+#include "src/ui/terminal/line.h"
+#include "third_party/abseil/absl/strings/str_cat.h"
+#include "third_party/abseil/absl/strings/str_join.h"
+#include "third_party/abseil/absl/strings/string_view.h"
+
+namespace ec {
+
+int TerminalUi::Main() noexcept {
+ BlockSigwinch();
+ TerminalLine tty;
+
+ State machine_state;
+ std::string input_buffer;
+ while (true) {
+ tty.SetLineImmediately(absl::StrCat(
+ absl::StrJoin(machine_state.stack, " ", FormatStackElement), " > ",
+ input_buffer));
+
+ char c = tty.GetChar();
+ if (c == tty.interrupt_char() || c == tty.quit_char()) {
+ // Somebody hit Ctrl-C or Ctrl-\.
+ return 0;
+ }
+ switch (c) {
+ case kControlD:
+ if (input_buffer.empty()) {
+ return 0;
+ }
+ tty.Beep();
+ break;
+
+ case kControlU:
+ input_buffer.clear();
+ break;
+
+ case '\n':
+ case '\r':
+ case ' ':
+ try {
+ std::vector<std::shared_ptr<const Term>> program;
+ if (input_buffer.empty()) {
+ program = {std::make_shared<ForeignProgramTerm>(BuiltinDup)};
+ } else {
+ program = ParseFromString(input_buffer);
+ }
+
+ State s = machine_state;
+ EvaluateAll(program, s);
+ machine_state = s;
+ input_buffer.clear();
+ } catch (const Error& e) {
+ tty.Beep();
+ }
+ break;
+
+ case '\x7f':
+ try {
+ if (input_buffer.empty()) {
+ State s = machine_state;
+ ForeignProgramTerm(BuiltinDrop).Evaluate(s);
+ machine_state = s;
+ } else {
+ input_buffer.pop_back();
+ }
+ } catch (const Error& e) {
+ tty.Beep();
+ }
+ break;
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ try {
+ std::vector<std::shared_ptr<const Term>> program =
+ ParseFromString(absl::StrCat(input_buffer, std::string(1, c)));
+ State s = machine_state;
+ EvaluateAll(program, s);
+ machine_state = s;
+ input_buffer.clear();
+ } catch (const Error& e) {
+ tty.Beep();
+ }
+ break;
+
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ input_buffer.push_back(c);
+ break;
+
+ default:
+ tty.Beep();
+ break;
+ }
+ }
+}
+
+} // namespace ec