// 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 #include #include #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> program; if (input_buffer.empty()) { program = {std::make_shared(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> 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