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