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
Diffstat:
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;