stamenStatic Menu Generator | 
          
| git clone git://git.dimitrijedobrota.com/stamen.git | 
| Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | 
| commit | c8ced3bdeaf1fe72949185cdc566b5fc69f11ddc | 
| parent | b833ffadb09c2e07d744ac2e30ecb0562d8b89be | 
| author | Dimitrije Dobrota < mail@dimitrijedobrota.com > | 
| date | Thu, 9 Nov 2023 20:26:34 +0000 | 
Add ability to generate c++ code from config
| M | include/menu.h | | | +++++++++++++++++++++ ---------------- | 
| A | src/generate.cpp | | | ++++++++++++++++++++++ | 
| M | src/main.cpp | | | ++++++++ ------ | 
| M | src/menu.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --------- | 
4 files changed, 105 insertions(+), 31 deletions(-)
diff --git a/ include/menu.h b/ include/menu.h
          @@ -20,40 +20,45 @@ 
          public:
        
        
              }
            };
          private:
            struct item_t {
              const std::string prompt;
              const std::string callback;
              const std::string prompt, callback;
              const callback_f func;
              item_t(const std::string &p, const std::string &c)
                  : prompt(p), callback(c) {}
              item_t(const std::string &p, const std::string &c,
                     const callback_f func = nullptr)
                  : prompt(p), callback(c), func(func) {}
              item_t(const json &j) : item_t(j["prompt"], j["callback"]) {}
            };
            Menu(const json &json_data)
                : name(json_data["name"]), code(json_data["code"]),
                  items({json_data["items"].begin(), json_data["items"].end()}) {}
            Menu(const std::string code, const callback_f callback)
                : name(code), code(code), items(), callback(callback) {}
          public:
            static void read(const std::string &s) {
              for (const auto &json_data : json::parse(std::fstream(s))) {
                lookup.insert({json_data["code"], Menu(json_data)});
              }
            }
            static int start() { return getMenu("main")(); }
            static int start() { return getMenu(entry)(); }
            static void insert(const std::string code, const callback_f callback) {
              lookup.insert({code, Menu(code, callback)});
            }
            static void print(const std::string code = "main", const int depth = 1);
            int operator()() const;
            static void print(const std::string &code = entry, const int depth = 1);
            static void generate(const std::string &code = entry);
            static int display(const std::string &name, const item_t items[], int size);
            int operator()() const {
              return callback ? callback() : display(name, items.data(), items.size());
            }
          private:
            Menu(const json &json_data)
                : name(json_data["name"]), code(json_data["code"]),
                  items({json_data["items"].begin(), json_data["items"].end()}) {}
            Menu(const std::string code, const callback_f callback)
                : name(code), code(code), items(), callback(callback) {}
            static std::unordered_map<std::string, Menu> lookup;
            static const std::string entry;
            static const Menu &getMenu(const std::string &code) {
              const auto it = lookup.find(code);
        
        diff --git a/ src/generate.cpp b/ src/generate.cpp
@@ -0,0 +1,22 @@
#include "json.hpp"
          #include <format>
          #include <fstream>
          #include <iostream>
          #include <string>
          using json = nlohmann::json;
          int main(const int argc, const char *argv[]) {
            for (int i = 1; i < argc; i++) {
              const char *filename = argv[i];
              for (const auto &menu : json::parse(std::fstream(filename))) {
                std::cout << std::format("{}({}):\n", (std::string)menu["name"],
                                         (std::string)menu["code"]);
                for (const auto &item : menu["items"]) {
                  std::cout << std::format("* {}({})\n", (std::string)item["prompt"],
                                           (std::string)item["callback"]);
                }
              }
            }
            return 0;
          }
        
        diff --git a/ src/main.cpp b/ src/main.cpp
          @@ -18,14 +18,16 @@ 
          int finish(void) {
        
        
            exit(0);
          }
          int foo(void) { exit(1); }
          int main(void) {
            Menu::read("menu.json");
            Menu::insert("algorithms", algorithms);
            Menu::insert("settings", settings);
            Menu::insert("finish", finish);
            Menu::print("main");
            Menu::start();
            // Menu::insert("algorithms", algorithms);
            // Menu::insert("settings", settings);
            // Menu::insert("finish", finish);
            Menu::generate();
            // Menu::print();
            // Menu::start();
            return 0;
          }
        
        diff --git a/ src/menu.cpp b/ src/menu.cpp
@@ -2,30 +2,32 @@
#include <cmath>
          #include <format>
          #include <iostream>
          #include <stack>
          #include <unordered_set>
          std::unordered_map<std::string, Menu> Menu::lookup;
          const std::string Menu::entry = "menu_main";
          int Menu::operator()() const {
            if (callback) return callback();
          int Menu::display(const std::string &name, const item_t items[], int size) {
            int choice;
            const int n = items.size(), digits = std::log10(n) + 1;
            const int digits = std::log10(size) + 1;
            while (true) {
              std::cout << std::format("{}:\n", name);
              for (auto i = 0ul; i < n; i++) {
              for (auto i = 0ul; i < size; i++) {
                std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].prompt);
              }
              while (true) {
                std::cout << "Choose an option: ";
                if (std::cin >> choice && choice >= -1 && choice < n) {
                if (std::cin >> choice && choice >= -1 && choice < size) {
                  if (choice == -1) {
                    std::cout << "choice: back\n";
                    return 1;
                  }
                  std::cout << std::format("Choice: {}\n\n", items[choice].prompt);
                  int res = getMenu(items[choice].callback)();
                  const item_t &chosen = items[choice];
                  std::cout << std::format("Choice: {}\n\n", chosen.prompt);
                  int res = chosen.func ? chosen.func() : getMenu(chosen.callback)();
                  if (--res) return res;
                  break;
        
        
          @@ -44,7 +46,50 @@ 
          int Menu::operator()() const {
        
        
            return 1;
          }
          void Menu::print(const std::string code, const int depth) {
          void Menu::generate(const std::string &code) {
            std::unordered_set<std::string> seen;
            std::vector<std::string> order;
            std::stack<std::string> st;
            st.push(code);
            while (!st.empty()) {
              if (!st.top().empty()) {
                const std::string &code = st.top();
                st.push("");
                for (const auto &[_, code, func] : getMenu(code).items) {
                  if (lookup.count(code)) st.push(code);
                }
                continue;
              }
              st.pop();
              const std::string &code = st.top();
              st.pop();
              if (seen.count(code)) continue;
              seen.insert(code);
              order.push_back(code);
            }
            for (const auto &code : order) {
              const Menu menu = getMenu(code);
              if (menu.callback) continue;
              std::cout << std::format("int {}(void) {{\n", menu.code);
              std::cout << std::format("\tstatic const Menu::item_t items[] = {{\n");
              for (const auto &item : menu.items) {
                std::cout << std::format("\t\t{{ \"{}\", \"{}\", {} }},\n", item.prompt,
                                         item.callback, item.callback);
              }
              std::cout << std::format("\t}};\n");
              std::cout << std::format("\treturn Menu::display(\"{}\", items, "
                                       "sizeof(items) / sizeof(Menu::item_t));\n",
                                       menu.name);
              std::cout << std::format("}}\n\n");
            }
          }
          void Menu::print(const std::string &code, const int depth) {
            const auto it = lookup.find(code);
            if (it == lookup.end()) return;
            const Menu &menu = it->second;