stamen

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

commit 472fad60cd717eef6ead0ed88668462e630f78c3
parent 45ebb3b798a9cf306ccfce512db8755e22cc472e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu, 13 Jun 2024 22:00:12 +0200

New .clang-format, full reformat

Diffstat:
M.clang-format | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mdemo/dynamic.cpp | 36++++++++++++++++++------------------
Mdemo/main.c | 26+++++++++++++-------------
Mdemo/main.cpp | 26+++++++++++++-------------
Minclude/menu.h | 120+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Minclude/stamen.h | 4++--
Msrc/c_bindings.cpp | 4++--
Msrc/generate.cpp | 92++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/menu.cpp | 85++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/stamen.cpp | 67++++++++++++++++++++++++++++++++++---------------------------------
10 files changed, 293 insertions(+), 249 deletions(-)

diff --git a/.clang-format b/.clang-format @@ -1,26 +1,45 @@ --- Language: Cpp -# BasedOnStyle: LLVM +# BasedOnStyle: Microsoft AccessModifierOffset: -2 -AlignAfterOpenBracket: true -AlignArrayOfStructures: Right -AlignConsecutiveMacros: true -AlignConsecutiveAssignments: None -AlignConsecutiveBitFields: None -AlignConsecutiveDeclarations: None +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false AlignEscapedNewlines: Right AlignOperands: Align AlignTrailingComments: true AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true -AllowShortEnumsOnASingleLine: true -AllowShortBlocksOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true -AllowShortFunctionsOnASingleLine: All +AllowShortFunctionsOnASingleLine: true AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false @@ -32,7 +51,7 @@ BinPackParameters: true BraceWrapping: AfterCaseLabel: false AfterClass: false - AfterControlStatement: Never + AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false @@ -49,8 +68,8 @@ BraceWrapping: SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: true -BreakBeforeBraces: Attach +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true @@ -58,10 +77,10 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true -ColumnLimit: 80 +ColumnLimit: 79 CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true @@ -71,6 +90,10 @@ DisableFormat: false EmptyLineAfterAccessModifier: Never EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true FixNamespaceComments: true ForEachMacros: - foreach @@ -100,9 +123,10 @@ IndentCaseBlocks: false IndentGotoLabels: true IndentPPDirectives: None IndentExternBlock: AfterExternBlock -IndentRequires: false -IndentWidth: 2 +IndentRequiresClause: true +IndentWidth: 4 IndentWrappedFunctionNames: false +InsertBraces: false InsertTrailingCommas: None JavaScriptQuotes: Leave JavaScriptWrapImports: true @@ -121,15 +145,19 @@ PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyReturnTypeOnItsOwnLine: 1000 PenaltyIndentedWhitespace: 0 PointerAlignment: Right PPIndentWidth: -1 ReferenceAlignment: Pointer ReflowComments: true +RemoveBracesLLVM: false +RequiresClausePosition: OwnLine +SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 SortIncludes: CaseSensitive SortJavaStaticImport: Before @@ -143,6 +171,16 @@ SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false SpaceAroundPointerQualifiers: Default SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyBlock: false @@ -165,7 +203,7 @@ StatementAttributeLikeMacros: StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION -TabWidth: 8 +TabWidth: 4 UseCRLF: false UseTab: Never WhitespaceSensitiveMacros: diff --git a/demo/dynamic.cpp b/demo/dynamic.cpp @@ -8,31 +8,31 @@ const stamen::display_f &stamen::display = stamen::builtin_display; int finish(int) { exit(1); } int operation1(int) { - std::cout << "1" << std::endl; - return 1; + std::cout << "1" << std::endl; + return 1; } int operation2(int) { - std::cout << "2" << std::endl; - return 1; + std::cout << "2" << std::endl; + return 1; } int operation3(int) { - std::cout << "3" << std::endl; - return 1; + std::cout << "3" << std::endl; + return 1; } int main() { - // read the configuration - stamen::read("./bin/demo_menu.conf"); - - // register free functions - stamen::insert("finish", finish); - stamen::insert("operation1", operation1); - stamen::insert("operation2", operation2); - stamen::insert("operation3", operation3); - - // start the menu on specific panel - stamen::dynamic("menu_main"); - return 0; + // read the configuration + stamen::read("./bin/demo_menu.conf"); + + // register free functions + stamen::insert("finish", finish); + stamen::insert("operation1", operation1); + stamen::insert("operation2", operation2); + stamen::insert("operation3", operation3); + + // start the menu on specific panel + stamen::dynamic("menu_main"); + return 0; } diff --git a/demo/main.c b/demo/main.c @@ -9,29 +9,29 @@ const stamen_display_f stamen_display = stamen_builtin_display; int operation1(void) { - printf("operation 1\n"); - printf("Some operation is done\n"); - return 1; + printf("operation 1\n"); + printf("Some operation is done\n"); + return 1; } int operation2(void) { - printf("operation 2\n"); - printf("Some other operation is done\n"); - return 1; + printf("operation 2\n"); + printf("Some other operation is done\n"); + return 1; } int operation3(void) { - printf("operation 3\n"); - printf("Yet another operation is done\n"); - return 1; + printf("operation 3\n"); + printf("Yet another operation is done\n"); + return 1; } int finish(void) { - printf("finishing...\n"); - exit(0); + printf("finishing...\n"); + exit(0); } int main(void) { - menu_main(0); - return 0; + menu_main(0); + return 0; } diff --git a/demo/main.cpp b/demo/main.cpp @@ -8,29 +8,29 @@ const stamen::display_f &stamen::display = stamen::builtin_display; int operation1(int) { - std::cout << "operation 1" << std::endl; - std::cout << "Some operation is done" << std::endl; - return 1; + std::cout << "operation 1" << std::endl; + std::cout << "Some operation is done" << std::endl; + return 1; } int operation2(int) { - std::cout << "operation 2" << std::endl; - std::cout << "Some other operation is done" << std::endl; - return 1; + std::cout << "operation 2" << std::endl; + std::cout << "Some other operation is done" << std::endl; + return 1; } int operation3(int) { - std::cout << "operation 3" << std::endl; - std::cout << "Yet another operation is done" << std::endl; - return 1; + std::cout << "operation 3" << std::endl; + std::cout << "Yet another operation is done" << std::endl; + return 1; } int finish(int) { - std::cout << "finishing..." << std::endl; - exit(0); + std::cout << "finishing..." << std::endl; + exit(0); } int main() { - menu_main(0); - return 0; + menu_main(0); + return 0; } diff --git a/include/menu.h b/include/menu.h @@ -12,82 +12,86 @@ namespace stamen { class Menu { - friend class Generator; + friend class Generator; - static std::unordered_map<std::string, Menu> menu_lookup; - static std::unordered_map<std::string, callback_f> free_lookup; - static std::string display_stub_default; + static std::unordered_map<std::string, Menu> menu_lookup; + static std::unordered_map<std::string, callback_f> free_lookup; + static std::string display_stub_default; - struct private_ctor_t {}; + struct private_ctor_t {}; -public: - // Tag type dispatch - Menu(private_ctor_t, const std::string &code, const std::string &prompt) - : Menu(code, prompt) {} + public: + // Tag type dispatch + Menu(private_ctor_t, const std::string &code, const std::string &prompt) + : Menu(code, prompt) {} - Menu(const Menu &) = delete; - Menu &operator=(const Menu &) = delete; + Menu(const Menu &) = delete; + Menu &operator=(const Menu &) = delete; - static int dynamic(const std::string &code) { - display_stub_default = code; - return display_stub(-1); - }; - static void read(const std::string &s); - static void print(const std::string &entry) { print(entry, 1); } - static void insert(const std::string &s, callback_f callback) { - free_lookup.emplace(s, callback); - } + static int dynamic(const std::string &code) { + display_stub_default = code; + return display_stub(-1); + }; + static void read(const std::string &s); + static void print(const std::string &entry) { print(entry, 1); } + static void insert(const std::string &s, callback_f callback) { + free_lookup.emplace(s, callback); + } - [[nodiscard]] const std::string &getCode() const { return code; } - [[nodiscard]] const std::string &getTitle() const { return title; } + [[nodiscard]] const std::string &getCode() const { return code; } + [[nodiscard]] const std::string &getTitle() const { return title; } - [[nodiscard]] const item_t *getItemv() const { return entries.items.data(); } - [[nodiscard]] std::size_t getSize() const { return entries.items.size(); } + [[nodiscard]] const item_t *getItemv() const { + return entries.items.data(); + } + [[nodiscard]] std::size_t getSize() const { return entries.items.size(); } - [[nodiscard]] const std::string &getCode(std::size_t idx) const { - return entries.codes[idx].code; - } + [[nodiscard]] const std::string &getCode(std::size_t idx) const { + return entries.codes[idx].code; + } - [[nodiscard]] const std::string &getPrompt(std::size_t idx) const { - return entries.codes[idx].prompt; - } + [[nodiscard]] const std::string &getPrompt(std::size_t idx) const { + return entries.codes[idx].prompt; + } - [[nodiscard]] callback_f getCallback(std::size_t idx) const { - return entries.items[idx].callback; - } + [[nodiscard]] callback_f getCallback(std::size_t idx) const { + return entries.items[idx].callback; + } -private: - Menu(std::string code, std::string prompt) - : code(std::move(code)), title(std::move(prompt)) {} + private: + Menu(std::string code, std::string prompt) + : code(std::move(code)), title(std::move(prompt)) {} - static void print(const std::string &entry, const int depth); - static int display_stub(int idx); + static void print(const std::string &entry, const int depth); + static int display_stub(int idx); - struct Entries { - struct code_t { - const std::string code; - const std::string prompt; - }; + struct Entries { + struct code_t { + std::string code; + std::string prompt; + }; - ~Entries() { - for (const auto [_, prompt] : items) delete[] prompt; - } + ~Entries() { + for (const auto [_, prompt] : items) { + delete[] prompt; + } + } - std::vector<code_t> codes; - std::vector<item_t> items; + std::vector<code_t> codes; + std::vector<item_t> items; - void insert(const std::string &code, const std::string &prompt, - callback_f callback = display_stub) { - char *buffer = new char[prompt.size() + 1]; - strcpy(buffer, prompt.c_str()); - items.emplace_back(callback, buffer); + void insert(const std::string &code, const std::string &prompt, + callback_f callback = display_stub) { + char *buffer = new char[prompt.size() + 1]; + strcpy(buffer, prompt.c_str()); + items.emplace_back(callback, buffer); - codes.emplace_back(code, prompt); - } - }; + codes.emplace_back(code, prompt); + } + }; - const std::string code, title; - Entries entries; + const std::string code, title; + Entries entries; }; } // namespace stamen diff --git a/include/stamen.h b/include/stamen.h @@ -10,8 +10,8 @@ typedef int (*stamen_callback_f)(int); typedef struct stamen_item_t stamen_item_t; struct stamen_item_t { - stamen_callback_f callback; - const char *prompt; + stamen_callback_f callback; + const char *prompt; }; typedef int (*stamen_display_f)(const char *, const stamen_item_t[], int); diff --git a/src/c_bindings.cpp b/src/c_bindings.cpp @@ -8,12 +8,12 @@ int stamen_dynamic(const char *code) { return dynamic(code); } void stamen_read(const char *filename) { return read(filename); } void stamen_insert(const char *code, stamen_callback_f callback) { - return insert(code, callback); + return insert(code, callback); } int stamen_builtin_display(const char *title, const stamen_item_t itemv[], int size) { - return builtin_display(title, itemv, size); + return builtin_display(title, itemv, size); } } // namespace stamen diff --git a/src/generate.cpp b/src/generate.cpp @@ -9,47 +9,47 @@ namespace stamen { class Generator { -public: - static void generateInclude(std::ostream &os, bool cpp) { - os << "#ifndef STAMEN_MENU_H\n"; - os << "#define STAMEN_MENU_H\n\n"; + public: + static void generateInclude(std::ostream &os, bool cpp) { + os << "#ifndef STAMEN_MENU_H\n"; + os << "#define STAMEN_MENU_H\n\n"; - if (cpp) os << "#include \"stamen.hpp\"\n\n"; - else os << "#include \"stamen.h\"\n\n"; + if (cpp) os << "#include \"stamen.hpp\"\n\n"; + else os << "#include \"stamen.h\"\n\n"; - for (const auto &[code, menu] : Menu::menu_lookup) { - os << std::format("int {}(int);\n", menu.getCode()); - } + for (const auto &[code, menu] : Menu::menu_lookup) { + os << std::format("int {}(int);\n", menu.getCode()); + } - os << "\n#endif\n"; - } + os << "\n#endif\n"; + } - static void generateSource(std::ostream &os, bool cpp) { - if (cpp) os << "#include \"stamen.hpp\"\n\n"; - else os << "#include \"stamen.h\"\n\n"; + static void generateSource(std::ostream &os, bool cpp) { + if (cpp) os << "#include \"stamen.hpp\"\n\n"; + else os << "#include \"stamen.h\"\n\n"; - os << "#include \"shared.h\"\n\n"; - for (const auto &[code, menu] : Menu::menu_lookup) { - os << std::format("int {}(int) {{\n", menu.getCode()); + os << "#include \"shared.h\"\n\n"; + for (const auto &[code, menu] : Menu::menu_lookup) { + os << std::format("int {}(int) {{\n", menu.getCode()); - if (cpp) os << "\tstatic const stamen::item_t items[] = "; - else os << "\tstatic const stamen_item_t items[] = "; + if (cpp) os << "\tstatic const stamen::item_t items[] = "; + else os << "\tstatic const stamen_item_t items[] = "; - os << "{\n"; - for (int i = 0; i < menu.getSize(); i++) { - os << "\t\t{ " << menu.getCode(i); - os << ", \"" << menu.getPrompt(i) << "\" },\n"; - } - os << "\t};\n"; + os << "{\n"; + for (int i = 0; i < menu.getSize(); i++) { + os << "\t\t{ " << menu.getCode(i); + os << ", \"" << menu.getPrompt(i) << "\" },\n"; + } + os << "\t};\n"; - if (cpp) os << "\treturn stamen::display"; - else os << "\treturn stamen_display"; + if (cpp) os << "\treturn stamen::display"; + else os << "\treturn stamen_display"; - os << std::format("(\"{}\"", menu.getTitle()); - os << ", items, sizeof(items) / sizeof(items[0]));\n"; - os << "}\n\n"; + os << std::format("(\"{}\"", menu.getTitle()); + os << ", items, sizeof(items) / sizeof(items[0]));\n"; + os << "}\n\n"; + } } - } }; } // namespace stamen @@ -57,25 +57,25 @@ public: using namespace stamen; int main(const int argc, const char *argv[]) { - const auto args = std::span(argv, size_t(argc)); + const auto args = std::span(argv, size_t(argc)); - if (argc != 2 && argc != 3) { - std::cout << argv[0] << " config_file [c/cpp]" << std::endl; - return 1; - } + if (argc != 2 && argc != 3) { + std::cout << argv[0] << " config_file [c/cpp]" << std::endl; + return 1; + } - const bool cpp = argc == 2 || std::string(args[2]) == "cpp"; + const bool cpp = argc == 2 || std::string(args[2]) == "cpp"; - std::string path = args[1]; - Menu::read(path); + std::string path = args[1]; + Menu::read(path); - std::string::size_type pos = path.rfind('.'); - std::string base = pos != std::string::npos ? path.substr(0, pos) : path; - std::string ext = cpp ? "pp" : ""; + std::string::size_type pos = path.rfind('.'); + std::string base = pos != std::string::npos ? path.substr(0, pos) : path; + std::string ext = cpp ? "pp" : ""; - std::ofstream source(base + ".c" + ext), include(base + ".h" + ext); - Generator::generateSource(source, cpp); - Generator::generateInclude(include, cpp); + std::ofstream source(base + ".c" + ext), include(base + ".h" + ext); + Generator::generateSource(source, cpp); + Generator::generateInclude(include, cpp); - return 0; + return 0; } diff --git a/src/menu.cpp b/src/menu.cpp @@ -15,62 +15,63 @@ std::unordered_map<std::string, callback_f> Menu::free_lookup; std::string Menu::display_stub_default; void Menu::read(const std::string &s) { - std::string line, delim, code, prompt; - std::fstream fs(s); - char tmp = 0; + std::string line, delim, code, prompt; + std::fstream fs(s); + char tmp = 0; - auto last = menu_lookup.end(); - while (std::getline(fs, line)) { - if (line.empty()) continue; - std::istringstream ss(line); - ss >> delim >> code; - ss.ignore(1, ' '), std::getline(ss, prompt); - if (delim == "+") { - const auto [iter, succ] = menu_lookup.emplace( - std::piecewise_construct, std::forward_as_tuple(code), - std::forward_as_tuple(private_ctor_t{}, code, prompt)); - last = iter; - } else { - last->second.entries.insert(code, prompt); + auto last = menu_lookup.end(); + while (std::getline(fs, line)) { + if (line.empty()) continue; + std::istringstream ss(line); + ss >> delim >> code; + ss.ignore(1, ' '), std::getline(ss, prompt); + if (delim == "+") { + const auto [iter, succ] = menu_lookup.emplace( + std::piecewise_construct, std::forward_as_tuple(code), + std::forward_as_tuple(private_ctor_t{}, code, prompt)); + last = iter; + } else { + last->second.entries.insert(code, prompt); + } } - } } void Menu::print(const std::string &code, const int depth) { - const auto it = menu_lookup.find(code); - if (it == menu_lookup.end()) return; - const Menu *menu = &it->second; + const auto it = menu_lookup.find(code); + if (it == menu_lookup.end()) return; + const Menu *menu = &it->second; - if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code); + if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code); - for (int i = 0; i < menu->getSize(); i++) { - std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '), - menu->getPrompt(i), menu->getCode(i)); - menu->print(code, depth + 1); - } + for (int i = 0; i < menu->getSize(); i++) { + std::cout << std::string(depth << 1, ' '); + std::cout << menu->getPrompt(i); + std::cout << std::format(" ({})\n", menu->getCode(i)); + menu->print(code, depth + 1); + } } int Menu::display_stub(int idx) { - static std::deque<const Menu *> st; + static std::deque<const Menu *> st; - const std::string &code = - st.size() ? st.back()->getCode(idx) : display_stub_default; + const std::string &code = + st.size() ? st.back()->getCode(idx) : display_stub_default; - const auto ml_it = menu_lookup.find(code); - if (ml_it != menu_lookup.end()) { - const Menu &menu = ml_it->second; - st.push_back(&menu); - int ret = stamen_builtin_display(menu.title.c_str(), menu.getItemv(), - menu.getSize()); - st.pop_back(); - return ret; - } + const auto ml_it = menu_lookup.find(code); + if (ml_it != menu_lookup.end()) { + const Menu &menu = ml_it->second; + st.push_back(&menu); + int ret = builtin_display(menu.title.c_str(), menu.getItemv(), + menu.getSize()); + st.pop_back(); + return ret; + } - const auto fl_it = free_lookup.find(code); - if (fl_it != free_lookup.end()) { return fl_it->second(0); } + const auto fl_it = free_lookup.find(code); + if (fl_it != free_lookup.end()) { return fl_it->second(0); } - std::cout << "Stamen: nothing to do..." << std::endl; - return 1; + std::cout << "Stamen: nothing to do..." << std::endl; + return 1; } } // namespace stamen diff --git a/src/stamen.cpp b/src/stamen.cpp @@ -12,48 +12,49 @@ namespace stamen { int dynamic(const char *code) { return Menu::dynamic(code); } void read(const char *filename) { Menu::read(filename); } void insert(const char *code, callback_f callback) { - Menu::insert(code, callback); + Menu::insert(code, callback); } int builtin_display(const char *title, const item_t itemv[], int size) { - const size_t digits = size_t(std::log10(size)) + 1; - const auto items = std::span(itemv, size_t(size)); - int choice = 0; - - while (true) { - std::cout << std::format("{}:\n", title); - for (auto i = 0ul; i < size; i++) { - std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].prompt); - } + const size_t digits = size_t(std::log10(size)) + 1; + const auto items = std::span(itemv, size_t(size)); + int choice = 0; while (true) { - std::cout << "Choose an option: "; - if (std::cin >> choice && choice >= -1 && choice < (int)size) { - if (choice == -1) { - std::cout << "Choice: back\n"; - return 1; + std::cout << std::format("{}:\n", title); + for (auto i = 0ul; i < size; i++) { + std::cout << std::format(" {:{}}. {}\n", i, digits, + items[i].prompt); } - std::cout << std::format("Choice: {}\n\n", items[choice].prompt); - const int res = items[choice].callback(choice); - if (res > 1) - return res - 1; - else - break; - - } else if (std::cin.eof()) { - std::cerr << "encountered end of input!\n"; - return std::numeric_limits<int>::max(); - } else { - std::cin.clear(); - std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); - } - std::cout << "Invalid option, please choose again!\n"; + while (true) { + std::cout << "Choose an option: "; + if (std::cin >> choice && choice >= -1 && choice < (int)size) { + if (choice == -1) { + std::cout << "Choice: back\n"; + return 1; + } + + std::cout << std::format("Choice: {}\n\n", + items[choice].prompt); + const int res = items[choice].callback(choice); + if (res > 1) return res - 1; + else break; + + } else if (std::cin.eof()) { + std::cerr << "encountered end of input!\n"; + return std::numeric_limits<int>::max(); + } else { + std::cin.clear(); + std::cin.ignore(std::numeric_limits<std::streamsize>::max(), + '\n'); + } + std::cout << "Invalid option, please choose again!\n"; + } + std::cout << std::endl; } - std::cout << std::endl; - } - return 1; + return 1; } } // namespace stamen