From 473b7ca97d9f2bed849ab902e8401ced42dba9eb Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 16:30:13 +0200 Subject: [PATCH] UI: Make interactive mode more interactive --- src/lang/interpreter.cc | 4 +-- src/lang/lang.cc | 15 +++++--- src/rt/core/builtin.cc | 8 +++++ src/rt/ui.h | 21 +++++++++-- src/rt/ui/mermaid.cc | 77 ++++++++++++++++++++++++++++++++++------- 5 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index 12f4517..db3b599 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -534,9 +534,9 @@ namespace verona::interpreter } }; - void start(trieste::Node main_body, bool interactive) + void start(trieste::Node main_body, int step_counter) { - rt::ui::MermaidUI ui(interactive); + rt::ui::MermaidUI ui(step_counter); size_t initial = rt::pre_run(&ui); diff --git a/src/lang/lang.cc b/src/lang/lang.cc index 4155039..fced124 100644 --- a/src/lang/lang.cc +++ b/src/lang/lang.cc @@ -3,6 +3,7 @@ #include "interpreter.h" #include "trieste/driver.h" +#include #include using namespace trieste; @@ -21,17 +22,23 @@ std::pair>> extract_bytecode_pass() namespace verona::interpreter { - void start(trieste::Node main_body, bool interactive); + void start(trieste::Node main_body, int step_counter); } struct CLIOptions : trieste::Options { - bool iterative = false; + int step_counter = std::numeric_limits::max(); void configure(CLI::App& app) { app.add_flag( - "-i,--interactive", iterative, "Run the interpreter iteratively"); + "-i,--interactive", + [&](auto) { step_counter = 0; }, + "Run the interpreter iteratively"); + app.add_option( + "-s,--step", + step_counter, + "Step n instructions before entering interactive mode"); } }; @@ -48,7 +55,7 @@ int load_trieste(int argc, char** argv) if (build_res == 0 && result->has_value()) { - verona::interpreter::start(result->value(), options.iterative); + verona::interpreter::start(result->value(), options.step_counter); } return build_res; } diff --git a/src/rt/core/builtin.cc b/src/rt/core/builtin.cc index 5dae61d..ee3a8b2 100644 --- a/src/rt/core/builtin.cc +++ b/src/rt/core/builtin.cc @@ -57,6 +57,14 @@ namespace rt::core return std::nullopt; }); + + add_builtin("breakpoint", [mermaid](auto, auto, auto args) { + assert(args == 0); + + mermaid->break_next(); + + return std::nullopt; + }); } void ctor_builtins() diff --git a/src/rt/ui.h b/src/rt/ui.h index d77e250..8030560 100644 --- a/src/rt/ui.h +++ b/src/rt/ui.h @@ -33,7 +33,12 @@ namespace rt::ui friend class MermaidDiagram; friend void core::mermaid_builtins(ui::UI* ui); - bool interactive; + /// @brief Indicates if this is the first break and the help message should + /// be printed. + bool first_break = true; + /// @brief Indicates how many steps should be taken until entering + /// interactive mode again. + int steps; std::string path; std::ofstream out; @@ -45,10 +50,22 @@ namespace rt::ui std::set always_hide; public: - MermaidUI(bool interactive); + MermaidUI(int step_counter); void output(std::vector& roots, std::string message); + void next_action(); + + void break_next() + { + steps = 0; + } + + bool should_break() + { + return steps == 0; + } + bool is_mermaid() { return true; diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 92911ee..5b564c6 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -3,6 +3,7 @@ #include "../ui.h" #include +#include #include #include #include @@ -177,21 +178,22 @@ namespace rt::ui } }; - MermaidUI::MermaidUI(bool interactive_) : interactive(interactive_) + MermaidUI::MermaidUI(int step_counter) : steps(step_counter) { path = "mermaid.md"; - - if (!interactive) - { - // Will be opened by the output function. - out.open(path); - } } void MermaidUI::output( std::vector& roots, std::string message) { - if (interactive) + // Reset the file if this is a breakpoint + if (should_break() && out.is_open()) + { + out.close(); + } + + // Open the file if it's not open + if (!out.is_open()) { out.open(path); } @@ -203,11 +205,62 @@ namespace rt::ui MermaidDiagram diag(this); diag.draw(roots); - if (interactive) + if (should_break()) { - out.close(); - std::cout << "Press a key!" << std::endl; - getchar(); + out.flush(); + next_action(); + } + else + { + steps -= 1; + } + } + + void print_help() + { + std::cout << "Commands:" << std::endl; + std::cout << "- s : Run n step (default n = 0) [Default]" << std::endl; + std::cout << "- r : Runs until the next break point" << std::endl; + std::cout << "- h : Prints this message " << std::endl; + } + + void MermaidUI::next_action() + { + if (first_break) + { + print_help(); + first_break = false; + } + + while (true) + { + std::cout << "> "; + std::string line; + std::getline(std::cin, line); + std::istringstream iss(line); + std::string command; + iss >> command; + + if (command == "s" || line.empty()) + { + int n = 0; + steps = (iss >> n) ? n : 0; + + return; + } + else if (command == "r") + { + steps = std::numeric_limits::max(); + return; + } + else if (command == "h") + { + print_help(); + } + else + { + std::cerr << "Unknown command. Type 'h' for help." << std::endl; + } } } } // namespace rt::ui