stamen

Stamen - static menu generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE

commit 260569531d18b4c35adeaa7b53c866ebea1e2d28
parent 0ab8d3b1b0cae32d598a861f4fa04f95b348d54c
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Tue,  7 Nov 2023 01:37:21 +0000

Refactoring

* Better initializastion of function lookup
* Consturctor now reads configuration directly
* More consistent menu display
* Remove menu.cpp
* Renaming
* Start menu with operator()

Diffstat:
MCMakeLists.txt | 2+-
Minclude/menu.h | 72+++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/CMakeLists.txt | 6+-----
Msrc/display.cpp | 24+++++++++++++++---------
Msrc/main.cpp | 12++++++++----
Msrc/menu.cpp | 9---------
6 files changed, 66 insertions(+), 59 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Menu - VERSION 0.0.1 + VERSION 0.0.2 DESCRIPTION "Experimentation with dinamic menus" LANGUAGES CXX ) diff --git a/include/menu.h b/include/menu.h @@ -9,7 +9,6 @@ #include <vector> using json = nlohmann::json; -using std::string, std::vector; class EMenu_callback : std::exception { virtual const char *what() const noexcept override { @@ -25,49 +24,60 @@ class EMenu_call : std::exception { class Menu { public: - typedef int (*Menu_f)(void); - - Menu() : function_lookup() {} - Menu(const string &s) : Menu() { - std::fstream f(s); - Read(f); + typedef int (*callback_f)(void); + + Menu(const std::string &s) { + for (const auto &menu : json::parse(std::fstream(s))) { + const json &items = menu["items"]; + const function_t *mf = + new function_t(*this, menu["name"], {items.begin(), items.end()}); + lookup.insert({menu["code"], callback_t(mf)}); + } } - void Start() const { get_callback("main")(); } + void operator()() const { get_callback("main")(); } - void Read(std::istream &is); - Menu &Register(const string &s, Menu_f f) { - function_lookup.insert({s, f}); - return *this; + struct record_t { + const std::string code; + const callback_f callback; + }; + + void insert(const record_t &record) { + lookup.insert({record.code, record.callback}); + } + void insert(const std::vector<record_t> &records) { + for (const auto &record : records) { insert(record); } } private: - struct Menu_item { - const string prompt; - const string callback; + struct item_t { + const std::string prompt; + const std::string callback; - Menu_item(const string &p, const string &c) : prompt(p), callback(c) {} - Menu_item(const json &j) : Menu_item(j["prompt"], j["callback"]) {} + item_t(const std::string &p, const std::string &c) + : prompt(p), callback(c) {} + item_t(const json &j) : item_t(j["prompt"], j["callback"]) {} }; - struct Menu_function { - Menu_function(const Menu &m, const string &n, const vector<Menu_item> &i) + struct function_t { + function_t(const Menu &m, const std::string &n, + const std::vector<item_t> &i) : menu(m), name(n), items(i) {} int display() const; private: const Menu &menu; - const string name; - const vector<Menu_item> items; + const std::string name; + const std::vector<item_t> items; }; - struct Menu_callback { - const Menu_f func = nullptr; - const Menu_function *menu_func = nullptr; + struct callback_t { + const function_t *menu_func = nullptr; + const callback_f func = nullptr; - Menu_callback(const Menu_f f) : func(f) {} - Menu_callback(const Menu_function *f) : menu_func(f) {} + callback_t(const callback_f f) : func(f) {} + callback_t(const function_t *f) : menu_func(f) {} int operator()() const { if (!func && !menu_func) throw EMenu_callback(); @@ -75,13 +85,13 @@ private: } }; - const Menu_callback &get_callback(const string &s) const { - auto it = function_lookup.find(s); - if (it == function_lookup.end()) throw EMenu_call(); - return (*it).second; + const callback_t &get_callback(const std::string &s) const { + const auto it = lookup.find(s); + if (it == lookup.end()) throw EMenu_call(); + return it->second; } - std::unordered_map<string, Menu_callback> function_lookup; + std::unordered_map<std::string, callback_t> lookup; }; #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -1,5 +1,4 @@ add_library(menu - menu.cpp display.cpp ) @@ -7,10 +6,7 @@ target_include_directories(menu PUBLIC ../include ) - -add_executable(demo - main.cpp -) +add_executable(demo main.cpp) target_link_libraries(demo PRIVATE menu diff --git a/src/display.cpp b/src/display.cpp @@ -1,24 +1,30 @@ #include "menu.h" +#include <cmath> +#include <format> #include <iostream> -int Menu::Menu_function::display() const { +int Menu::function_t::display() const { int choice; - while (true) { - std::cout << name << std::endl; - for (auto i = 0ul; i < items.size(); i++) - std::cout << i << ". " << items[i].prompt << std::endl; + const int n = items.size(), digits = std::log10(n) + 1; + while (true) { + std::cout << std::format("{}:\n", name); + for (auto i = 0ul; i < n; 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 < (int)items.size()) { + if (std::cin >> choice && choice >= -1 && choice < n) { if (choice == -1) { - std::cout << "Back" << items[choice].prompt << "\n"; + std::cout << "choice: back\n"; return 1; } - std::cout << "Chosen: " << items[choice].prompt << "\n\n"; + + std::cout << std::format("Choice: {}\n\n", items[choice].prompt); int res = menu.get_callback(items[choice].callback)(); if (--res) return res; + break; } else if (std::cin.eof()) { std::cerr << "encountered end of input!\n"; @@ -27,7 +33,7 @@ int Menu::Menu_function::display() const { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); } - std::cout << "Invalid option, please choose again!" << std::endl; + std::cout << "Invalid option, please choose again!\n"; } std::cout << std::endl; } diff --git a/src/main.cpp b/src/main.cpp @@ -3,11 +3,13 @@ int algorithms(void) { std::cout << "algorithms" << std::endl; + std::cout << "nothing to do here" << std::endl; return 1; } int settings(void) { std::cout << "settings" << std::endl; + std::cout << "nothing to do here" << std::endl; return 1; } @@ -18,9 +20,11 @@ int finish(void) { int main(void) { Menu menu("menu.json"); - menu.Register("algorithms", algorithms) - .Register("settings", settings) - .Register("finish", finish); - menu.Start(); + menu.insert({ + {"algorithms", algorithms}, + { "settings", settings}, + { "finish", finish} + }); + menu(); return 0; } diff --git a/src/menu.cpp b/src/menu.cpp @@ -1,11 +1,2 @@ #include "menu.h" -void Menu::Read(std::istream &is) { - json file = json::parse(is); - for (auto &menu : file) { - const json &items = menu["items"]; - const Menu_function *mf = - new Menu_function(*this, menu["name"], {items.begin(), items.end()}); - function_lookup.insert({menu["code"], Menu_callback(mf)}); - } -}