From 3f7746f62a333dc1eb6cfaa93f49eb4f43fc9d8d Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Fri, 24 Oct 2025 21:16:16 +0200 Subject: [PATCH 01/10] Started work on CAPIO-CL util tool --- CMakeLists.txt | 34 ++++++++++++++++++ utilities/capiocl-utils.cpp | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 utilities/capiocl-utils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4973a33..262560c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ option(CAPIO_CL_BUILD_TESTS "Build CAPIO-CL test suite" OFF) option(BUILD_PYTHON_BINDINGS "Build python bindings for CAPIO-CL" OFF) option(ENABLE_COVERAGE "Enable code coverage collection" FALSE) option(ENABLE_COVERAGE_PIPELINE "Add dedicated target to execute and collect coverage" OFF) +option(BUILD_UTILS "Build CAPIO-CL utility binaries" OFF) if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options(-O0 -g) @@ -157,6 +158,39 @@ if(LIBANL) target_link_libraries(libcapio_cl PRIVATE ${LIBANL}) endif () + +##################################### +# CAPIO-CL Utilities +##################################### + +if (BUILD_UTILS) + + FetchContent_Declare( + args + GIT_REPOSITORY https://github.com/Taywee/args.git + GIT_TAG 6.4.7 + ) + + set(ARGS_BUILD_EXAMPLE OFF CACHE INTERNAL "") + set(ARGS_BUILD_UNITTESTS OFF CACHE INTERNAL "") + FetchContent_MakeAvailable(args) + + add_executable(capiocl_utils + utilities/capiocl-utils.cpp + ${CAPIO_SRC} + ${CAPIO_CL_HEADERS}) + + target_include_directories(capiocl_utils PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${jsoncons_SOURCE_DIR}/include + ${CAPIOCL_JSON_SCHEMAS_DIRECTORY} + ${args_SOURCE_DIR} + ) + + target_link_libraries(capiocl_utils PUBLIC) +endif (BUILD_UTILS) + ##################################### # Install rules ##################################### diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp new file mode 100644 index 0000000..da0a39d --- /dev/null +++ b/utilities/capiocl-utils.cpp @@ -0,0 +1,70 @@ +#include +#include + +#include "capiocl.hpp" + +constexpr char capio_cl_header_help[] = R"( + ______ ______ _______ ______ ______ ______ __ + / \ / \ | \| \ / \ / \ | \ +| $$$$$$\| $$$$$$\| $$$$$$$\\$$$$$$| $$$$$$\ | $$$$$$\| $$ +| $$ \$$| $$__| $$| $$__/ $$ | $$ | $$ | $$ ______ | $$ \$$| $$ +| $$ | $$ $$| $$ $$ | $$ | $$ | $$| \| $$ | $$ +| $$ __ | $$$$$$$$| $$$$$$$ | $$ | $$ | $$ \$$$$$$| $$ __ | $$ +| $$__/ \| $$ | $$| $$ _| $$_ | $$__/ $$ | $$__/ \| $$_____ + \$$ $$| $$ | $$| $$ | $$ \ \$$ $$ \$$ $$| $$ \ + \$$$$$$ \$$ \$$ \$$ \$$$$$$ \$$$$$$ \$$$$$$ \$$$$$$$$ + + CAPIO-CL Utilities +)"; + +int main(int argc, char **argv) { + std::cout << capio_cl_header_help << std::endl; + args::ArgumentParser parser( + "CAPIO-CL Utilities", + "Developed by Marco Edoardo Santimaria \n marcoedoardo.santimaria@unito.it"); + args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"}); + args::Group arguments(parser, "Arguments"); + args::ValueFlag validate( + arguments, "path", "Validate a CAPIO-CL configuration file", {'v', "validate"}); + args::Flag builder(arguments, "build", "Interactively build a CAPIO-CL configuration file", + {'b', "build"}); + + try { + parser.ParseCLI(argc, argv); + } catch (const args::Completion &e) { + std::cout << e.what(); + return 0; + } catch (const args::Help &) { + std::cout << parser; + return 0; + } catch (const args::ParseError &e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return 1; + } + + if (validate) { + const std::string path = args::get(validate); + try { + auto parsed = capiocl::Parser::parse(path); + } catch (const capiocl::ParserException &e) { + std::cerr << std::endl + << "\t+==================================================+\n" + "\t|\033[0;31m Input File is NOT a VALID configuration file \033[0m |\n" + "\t+==================================================+" + << std::endl; + return 1; + } + + std::cout << std::endl + << "\t+=============================================+\n" + "\t|\033[0;32m Input File is a VALID configuration file \033[0m |\n" + "\t+=============================================+" + << std::endl; + return 0; + } + + if (builder) { + std::cout << "Starting CAPIO-CL builder..." << std::endl; + } +} \ No newline at end of file From 49bead3b9aec225d0b4d69e65c571d0f23944953 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Sun, 26 Oct 2025 10:27:47 +0100 Subject: [PATCH 02/10] wip --- utilities/capiocl-utils.cpp | 54 +++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index da0a39d..dc99bde 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "capiocl.hpp" @@ -17,6 +18,55 @@ constexpr char capio_cl_header_help[] = R"( CAPIO-CL Utilities )"; +std::vector split(const std::string &str, const char delimiter) { + std::vector result; + std::stringstream ss(str); + std::string token; + + while (std::getline(ss, token, delimiter)) { + result.push_back(token); + } + + return result; +} + +void capio_cl_builder() { + bool terminate = false; + + capiocl::Engine engine; + + while (!terminate) { + std::cout << "command> "; + std::string input; + getline(std::cin, input); + + auto args = split(input, ' '); + const auto &command = args[0]; + + if (command == "exit") { + terminate = true; + } else if (command == "help") { + std::cout << "Command availables:" << std::endl + << "\thelp: Show this menu" << std::endl + << "\texit: Exit from CAPIO-CL builder" << std::endl; + } else if (command == "save") { + if (args.size() < 2) { + std::cerr << "Please enter output filename. Args size: " << args.size() + << std::endl; + continue; + } + capiocl::Serializer::dump(engine, "TODO:WORKFLOW_NAME", args[1]); + } else if (command == "add") { + if (args.size() < 2) { + std::cerr << "Please enter input filename. Args size: " << args.size(); + continue; + } + engine.newFile(args[1]); + } + } + std::cout << "Bye!" << std::endl; +} + int main(int argc, char **argv) { std::cout << capio_cl_header_help << std::endl; args::ArgumentParser parser( @@ -47,7 +97,7 @@ int main(int argc, char **argv) { const std::string path = args::get(validate); try { auto parsed = capiocl::Parser::parse(path); - } catch (const capiocl::ParserException &e) { + } catch (...) { std::cerr << std::endl << "\t+==================================================+\n" "\t|\033[0;31m Input File is NOT a VALID configuration file \033[0m |\n" @@ -65,6 +115,6 @@ int main(int argc, char **argv) { } if (builder) { - std::cout << "Starting CAPIO-CL builder..." << std::endl; + capio_cl_builder(); } } \ No newline at end of file From c652f584d4ba694d821c6c7983ff6ffeaf90902c Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Sun, 26 Oct 2025 10:32:17 +0100 Subject: [PATCH 03/10] cnurses --- CMakeLists.txt | 4 +- utilities/capiocl-utils.cpp | 105 +++++++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 262560c..76224ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,7 @@ endif () ##################################### if (BUILD_UTILS) + find_package(Curses REQUIRED) FetchContent_Declare( args @@ -186,9 +187,10 @@ if (BUILD_UTILS) ${jsoncons_SOURCE_DIR}/include ${CAPIOCL_JSON_SCHEMAS_DIRECTORY} ${args_SOURCE_DIR} + ${CURSES_INCLUDE_DIR} ) - target_link_libraries(capiocl_utils PUBLIC) + target_link_libraries(capiocl_utils PUBLIC ${CURSES_LIBRARIES}) endif (BUILD_UTILS) ##################################### diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index dc99bde..af843e9 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -1,6 +1,10 @@ #include +#include +#include #include #include +#include +#include #include "capiocl.hpp" @@ -30,41 +34,78 @@ std::vector split(const std::string &str, const char delimiter) { return result; } +class Printer { + public: + void run(WINDOW *win, std::atomic &running) { + int counter = 0; + while (running) { + // Print a line on the right side + wprintw(win, "Right side output: %d\n", counter++); + wrefresh(win); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + } +}; + void capio_cl_builder() { - bool terminate = false; - - capiocl::Engine engine; - - while (!terminate) { - std::cout << "command> "; - std::string input; - getline(std::cin, input); - - auto args = split(input, ' '); - const auto &command = args[0]; - - if (command == "exit") { - terminate = true; - } else if (command == "help") { - std::cout << "Command availables:" << std::endl - << "\thelp: Show this menu" << std::endl - << "\texit: Exit from CAPIO-CL builder" << std::endl; - } else if (command == "save") { - if (args.size() < 2) { - std::cerr << "Please enter output filename. Args size: " << args.size() - << std::endl; - continue; - } - capiocl::Serializer::dump(engine, "TODO:WORKFLOW_NAME", args[1]); - } else if (command == "add") { - if (args.size() < 2) { - std::cerr << "Please enter input filename. Args size: " << args.size(); - continue; - } - engine.newFile(args[1]); + initscr(); // Start ncurses + cbreak(); // Disable line buffering + noecho(); // Don’t echo typed characters + curs_set(1); // Show the cursor + + int height, width; + getmaxyx(stdscr, height, width); + + int left_width = width / 2; + int right_width = width - left_width; + + // Create two windows + WINDOW *left = newwin(height, left_width, 0, 0); + WINDOW *right = newwin(height, right_width, 0, left_width); + + // Draw borders + box(left, 0, 0); + box(right, 0, 0); + mvwprintw(left, 0, 2, " Console "); + mvwprintw(right, 0, 2, " Output "); + wrefresh(left); + wrefresh(right); + + std::atomic running(true); + Printer printer; + std::thread printer_thread([&] { printer.run(right, running); }); + + // Interactive input on the left + char input[256]; + int row = 1; + while (true) { + mvwprintw(left, row, 2, "> "); + wrefresh(left); + + wgetnstr(left, input, sizeof(input) - 1); + + std::string cmd(input); + if (cmd == "quit" || cmd == "exit") { + break; + } + + row++; + if (row >= height - 1) { + werase(left); + box(left, 0, 0); + mvwprintw(left, 0, 2, " Console "); + row = 1; } + + mvwprintw(left, row, 2, "You typed: %s", input); + wrefresh(left); + row++; } - std::cout << "Bye!" << std::endl; + + running = false; + printer_thread.join(); + + endwin(); // Restore terminal } int main(int argc, char **argv) { From a035ddd7c0b10e9c6b39bb49904139a7bab5ccde Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Sun, 26 Oct 2025 10:49:50 +0100 Subject: [PATCH 04/10] Added ncurses in a good way --- utilities/capiocl-utils.cpp | 224 ++++++++++++++++++++++++++++-------- 1 file changed, 173 insertions(+), 51 deletions(-) diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index af843e9..b48fd43 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -34,80 +34,202 @@ std::vector split(const std::string &str, const char delimiter) { return result; } -class Printer { +// ----------------- Helper: capture std::cout ----------------- +class CaptureBuf : public std::stringbuf { public: - void run(WINDOW *win, std::atomic &running) { - int counter = 0; - while (running) { - // Print a line on the right side - wprintw(win, "Right side output: %d\n", counter++); - wrefresh(win); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } + std::string get_and_clear() { + std::string out = str(); + str(""); // clear + return out; } }; +// ----------------- Helper: render ANSI text in ncurses ----------------- +void render_ansi_to_window(WINDOW *win, const std::string &text, int start_y, int start_x) { + static bool colors_init = false; + if (!colors_init) { + start_color(); + use_default_colors(); + init_pair(30, COLOR_BLACK, -1); + init_pair(31, COLOR_RED, -1); + init_pair(32, COLOR_GREEN, -1); + init_pair(33, COLOR_YELLOW, -1); + init_pair(34, COLOR_BLUE, -1); + init_pair(35, COLOR_MAGENTA, -1); + init_pair(36, COLOR_CYAN, -1); + init_pair(37, COLOR_WHITE, -1); + colors_init = true; + } + + int y = start_y; + int x = start_x; + int attr_on = 0; + + auto set_color = [&](int code) { + if (code == 0) { + if (attr_on != 0) { + wattroff(win, COLOR_PAIR(attr_on)); + attr_on = 0; + } + return; + } + if (code >= 30 && code <= 37) { + if (attr_on != 0) { + wattroff(win, COLOR_PAIR(attr_on)); + } + wattron(win, COLOR_PAIR(code)); + attr_on = code; + } + }; + + for (size_t i = 0; i < text.size();) { + if (i + 2 < text.size() && text[i] == '\x1b' && text[i + 1] == '[') { + size_t mpos = text.find('m', i + 2); + if (mpos == std::string::npos) { + break; + } + std::string seq = text.substr(i + 2, mpos - (i + 2)); + std::stringstream ss(seq); + std::string tok; + while (getline(ss, tok, ';')) { + if (!tok.empty()) { + set_color(std::atoi(tok.c_str())); + } + } + i = mpos + 1; + continue; + } + + if (text[i] == '\n') { + y++; + x = start_x; + int maxy, maxx; + getmaxyx(win, maxy, maxx); + if (y >= maxy - 1) { + wscrl(win, 1); + y = maxy - 2; + } + ++i; + continue; + } + + // Printable char + mvwaddch(win, y, x, text[i]); + ++x; + int maxy, maxx; + getmaxyx(win, maxy, maxx); + if (x >= maxx - 1) { + x = start_x; + y++; + if (y >= maxy - 1) { + wscrl(win, 1); + y = maxy - 2; + } + } + ++i; + } +} + +// ----------------- Main function ----------------- void capio_cl_builder() { - initscr(); // Start ncurses - cbreak(); // Disable line buffering - noecho(); // Don’t echo typed characters - curs_set(1); // Show the cursor + initscr(); + cbreak(); + noecho(); + curs_set(1); int height, width; getmaxyx(stdscr, height, width); - int left_width = width / 2; - int right_width = width - left_width; + // Stack windows vertically + int cli_height = 6; + int top_height = height - cli_height; - // Create two windows - WINDOW *left = newwin(height, left_width, 0, 0); - WINDOW *right = newwin(height, right_width, 0, left_width); + WINDOW *top = newwin(top_height, width, 0, 0); + WINDOW *cli = newwin(cli_height, width, top_height, 0); - // Draw borders - box(left, 0, 0); - box(right, 0, 0); - mvwprintw(left, 0, 2, " Console "); - mvwprintw(right, 0, 2, " Output "); - wrefresh(left); - wrefresh(right); + scrollok(top, TRUE); + scrollok(cli, TRUE); - std::atomic running(true); - Printer printer; - std::thread printer_thread([&] { printer.run(right, running); }); + box(top, 0, 0); + box(cli, 0, 0); + mvwprintw(top, 0, 2, " Engine Output "); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + wrefresh(top); + wrefresh(cli); - // Interactive input on the left + capiocl::Engine engine; + bool terminate = false; char input[256]; - int row = 1; - while (true) { - mvwprintw(left, row, 2, "> "); - wrefresh(left); - wgetnstr(left, input, sizeof(input) - 1); + while (!terminate) { + // Prompt in bottom window + werase(cli); + box(cli, 0, 0); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + mvwprintw(cli, 2, 2, "command> "); + wmove(cli, 2, 11); + echo(); + wrefresh(cli); + + wgetnstr(cli, input, sizeof(input) - 1); + noecho(); - std::string cmd(input); - if (cmd == "quit" || cmd == "exit") { - break; + std::string line(input); + auto args = split(line, ' '); + if (args.empty()) { + continue; } + const std::string &command = args[0]; - row++; - if (row >= height - 1) { - werase(left); - box(left, 0, 0); - mvwprintw(left, 0, 2, " Console "); - row = 1; + if (command == "exit") { + terminate = true; + } else if (command == "help") { + mvwprintw(cli, 4, 2, + "Commands:\n" + "\thelp - Show this menu\n" + "\texit - Quit CAPIO-CL builder\n" + "\tsave - Save workflow\n" + "\tadd - Add new file\n"); + } else if (command == "save") { + if (args.size() < 2) { + mvwprintw(cli, 4, 2, "Error: missing filename\n"); + } else { + capiocl::Serializer::dump(engine, "TODO:WORKFLOW_NAME", args[1]); + } + } else if (command == "add") { + if (args.size() < 2) { + mvwprintw(cli, 4, 2, "Error: missing filename\n"); + } else { + engine.newFile(args[1]); + } + } else { + mvwprintw(cli, 4, 2, "Unknown command: %s\n", command.c_str()); } - mvwprintw(left, row, 2, "You typed: %s", input); - wrefresh(left); - row++; - } + // Capture engine output and render with ANSI colors + CaptureBuf cap; + std::streambuf *old_buf = std::cout.rdbuf(&cap); + engine.print(); + std::cout.flush(); + std::cout.rdbuf(old_buf); - running = false; - printer_thread.join(); + std::string out = cap.get_and_clear(); - endwin(); // Restore terminal -} + werase(top); + box(top, 0, 0); + mvwprintw(top, 0, 2, " Engine Output "); + render_ansi_to_window(top, out, 1, 2); + wrefresh(top); + // Clear CLI after each command + werase(cli); + box(cli, 0, 0); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + wrefresh(cli); + } + + endwin(); +} int main(int argc, char **argv) { std::cout << capio_cl_header_help << std::endl; args::ArgumentParser parser( From cf421ed7b6fd29682b2382242974c1ce367c6cb5 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Sun, 26 Oct 2025 15:46:09 +0100 Subject: [PATCH 05/10] wip --- CMakeLists.txt | 12 +- utilities/capio_cl_builder.h | 325 +++++++++++++++++++++++++++++++++++ utilities/capiocl-utils.cpp | 207 +--------------------- 3 files changed, 344 insertions(+), 200 deletions(-) create mode 100644 utilities/capio_cl_builder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 76224ed..1b21ae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option(BUILD_PYTHON_BINDINGS "Build python bindings for CAPIO-CL" OFF) option(ENABLE_COVERAGE "Enable code coverage collection" FALSE) option(ENABLE_COVERAGE_PIPELINE "Add dedicated target to execute and collect coverage" OFF) option(BUILD_UTILS "Build CAPIO-CL utility binaries" OFF) +option(ADD_BUILDER "Add ncurses based builder" ON) if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options(-O0 -g) @@ -164,7 +165,11 @@ endif () ##################################### if (BUILD_UTILS) - find_package(Curses REQUIRED) + find_package(Curses) + + if (NOT CURSES_FOUND) + message(FATAL_ERROR "ncurses not found. If you do not need the interactive builder, add -DADD_BUILDER=FALSE to cmake") + endif () FetchContent_Declare( args @@ -181,6 +186,11 @@ if (BUILD_UTILS) ${CAPIO_SRC} ${CAPIO_CL_HEADERS}) + if (ADD_BUILDER) + add_compile_definitions(capiocl_utils _INTERACTIVE_BUILDER) + endif () + + target_include_directories(capiocl_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h new file mode 100644 index 0000000..c9d05c2 --- /dev/null +++ b/utilities/capio_cl_builder.h @@ -0,0 +1,325 @@ +#ifndef CAPIO_CL_UI_H +#define CAPIO_CL_UI_H + +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr char HELP_MESSAGE_COMMANDS[] = + "\n" + "=====================================================================\n" + " CAPIO-CL BUILDER HELP \n" + "=====================================================================\n" + "\n" + "General Commands:\n" + " help Show this help menu\n" + " exit Quit CAPIO-CL builder\n" + " print Print current configuration\n" + " save Save configuration to \n" + "\n" + "Add Commands:\n" + " add file Add a new file to the workflow\n" + " add producer Add a producer process for \n" + " add consumer Add a consumer process for \n" + " add dependency Add dependency for \n" + "\n" + "Set Commands:\n" + " set name Set the workflow name\n" + " set memory Mark as stored in memory\n" + " set fs Mark as stored on filesystem\n" + " set permanent Mark as permanent\n" + " set exclude Exclude from workflow output\n" + " set directory Mark as directory\n" + " set file Mark as regular file\n" + "\n" + "Unset Commands:\n" + " unset permanent Remove 'permanent' flag from \n" + " unset exclude Remove 'exclude' flag from \n" + "\n" + "Delete Commands:\n" + " delete Delete a file from the configuration\n" + "\n" + "=====================================================================\n"; + +class CaptureBuf : public std::stringbuf { + public: + std::string get_and_clear() { + std::string out = str(); + str(""); // clear + return out; + } +}; +inline void render_ansi_to_window(WINDOW *win, const std::string &text, int start_y, int start_x) { + // Regex to match ANSI escape sequences (like color codes) + static const std::regex ansi_regex("\x1B\\[[0-9;?]*[ -/]*[@-~]"); + static const std::regex remove_capio_cl_pre(R"(\[CAPIO-CL [^\]]*\])"); + + std::string clean = std::regex_replace(text, ansi_regex, ""); + clean = std::regex_replace(clean, remove_capio_cl_pre, ""); + + int y = start_y; + int x = start_x; + int maxy, maxx; + getmaxyx(win, maxy, maxx); + + for (char c : clean) { + if (c == '\n') { + y++; + x = start_x; + } else { + mvwaddch(win, y, x, c); + x++; + } + + // Handle wrapping and scrolling + if (x >= maxx - 1) { + x = start_x; + y++; + } + if (y >= maxy - 1) { + wscrl(win, 1); + y = maxy - 2; + } + } + + wrefresh(win); +} + +inline void print_top_text(WINDOW *top, const std::string &title, const std::string &text) { + werase(top); + box(top, 0, 0); + mvwprintw(top, 0, 2, "%s", title.c_str()); + + render_ansi_to_window(top, text, 1, 2); + + wrefresh(top); + doupdate(); +} + +inline void print_server_state(WINDOW *top, capiocl::Engine engine) { + CaptureBuf cap; + std::streambuf *old_buf = std::cout.rdbuf(&cap); + engine.print(); + std::cout.flush(); + std::cout.rdbuf(old_buf); + print_top_text(top, " Engine Output ", cap.get_and_clear()); +} + +inline std::tuple handle_add_command(std::vector &args, + capiocl::Engine &engine) { + const std::string &add_type = args[0]; + std::string error_message; + bool error_occurred = false; + + if (add_type == "file") { + engine.newFile(args[1]); + } else if (add_type == "producer") { + std::string &producer_name = args[1]; + const std::string &target_file = args[2]; + engine.addProducer(target_file, producer_name); + } else if (add_type == "consumer") { + std::string &consumer_name = args[1]; + const std::string &target_file = args[2]; + engine.addConsumer(target_file, consumer_name); + } else if (add_type == "dependency") { + std::filesystem::path dependency(args[1]); + const std::string &target_file = args[2]; + engine.addFileDependency(target_file, dependency); + } else { + error_message = "Unknown subcommand for add: " + args[2]; + error_occurred = true; + } + + return {error_occurred, error_message}; +} + +inline std::tuple handle_save_command(std::vector &args, + capiocl::Engine &engine) { + std::string error_message; + bool error_occurred = false; + + if (args.size() < 2) { + error_message = "Missing filename"; + error_occurred = true; + } else { + capiocl::Serializer::dump(engine, "TODO:WORKFLOW_NAME", args[1]); + } + return {error_occurred, error_message}; +} + +inline std::tuple +handle_print_command([[maybe_unused]] std::vector &args, + [[maybe_unused]] capiocl::Engine &engine) { + return {false, ""}; +} + +inline std::tuple +handle_help_command([[maybe_unused]] std::vector &args, + [[maybe_unused]] capiocl::Engine &engine) { + return {true, ""}; +} + +inline std::tuple handle_set_command(std::vector &args, + capiocl::Engine &engine) { + + std::string error_message; + bool error_occurred = false; + const std::string &target = args[0]; + if (target == "workflow_name") { + error_message = " WARNING ", + "Setting workflow name is not yet supported by CAPIO-CL: " + args[1]; + error_occurred = true; + } else if (target == "memory") { + const std::string &target_file = args[1]; + engine.setStoreFileInMemory(target_file); + } else if (target == "fs") { + const std::string &target_file = args[1]; + engine.setStoreFileInFileSystem(target_file); + } else if (target == "permanent") { + const std::string &target_file = args[1]; + engine.setPermanent(target_file, true); + } else if (target == "exclude") { + const std::string &target_file = args[1]; + engine.setExclude(target_file, true); + } else if (target == "directory") { + const std::string &target_file = args[1]; + engine.setDirectory(target_file); + } else if (target == "file") { + const std::string &target_file = args[1]; + engine.setFile(target_file); + } else { + error_message = "Unknown subcommand for set: " + args[1]; + error_occurred = true; + } + return {error_occurred, error_message}; +} + +inline std::tuple handle_unset_command(std::vector &args, + capiocl::Engine &engine) { + + std::string error_message; + bool error_occurred = false; + const std::string &target = args[0]; + if (target == "permanent") { + const std::string &target_file = args[1]; + engine.setPermanent(target_file, false); + } else if (target == "exclude") { + const std::string &target_file = args[1]; + engine.setExclude(target_file, false); + } else { + error_message = "Unknown subcommand for set: " + args[1]; + error_occurred = true; + } + return {error_occurred, error_message}; +} + +inline std::tuple handle_delete_command(std::vector &args, + capiocl::Engine &engine) { + const std::string &file = args[0]; + engine.remove(file); + + return {false, ""}; +} + +inline void capio_cl_builder() { + initscr(); + cbreak(); + noecho(); + curs_set(1); + + int height, width; + getmaxyx(stdscr, height, width); + + // Stack vertically + int cli_height = 10; + int top_height = height - cli_height; + + WINDOW *top = newwin(top_height, width, 0, 0); + WINDOW *cli = newwin(cli_height, width, top_height, 0); + + scrollok(top, TRUE); + scrollok(cli, TRUE); + + box(top, 0, 0); + box(cli, 0, 0); + mvwprintw(top, 0, 2, " Engine Output "); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + wrefresh(top); + wrefresh(cli); + + capiocl::Engine engine; + bool terminate = false; + char input[256]; + + print_server_state(top, engine); + + std::unordered_map (*)(std::vector &, + capiocl::Engine &)> + command_handlers; + + command_handlers["add"] = &handle_add_command; + command_handlers["save"] = &handle_save_command; + command_handlers["print"] = &handle_print_command; + command_handlers["help"] = &handle_help_command; + command_handlers["set"] = &handle_set_command; + command_handlers["unset"] = &handle_unset_command; + + while (!terminate) { + + std::string error_message; + bool error_occurred = false; + + werase(cli); + box(cli, 0, 0); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + mvwprintw(cli, 2, 2, "command> "); + wmove(cli, 2, 11); + echo(); + wrefresh(cli); + + wgetnstr(cli, input, sizeof(input) - 1); + noecho(); + + std::string line(input); + auto args = split(line, ' '); + if (args.empty()) { + continue; + } + + std::string command = args.front(); + args.erase(args.begin()); + + if (command == "exit") { + terminate = true; + continue; + } + + if (command_handlers.find(command) != command_handlers.end()) { + std::tie(error_occurred, error_message) = command_handlers[command](args, engine); + } else { + error_message = "Unknown command: " + command; + error_occurred = true; + } + + if (error_occurred) { + error_message += HELP_MESSAGE_COMMANDS; + print_top_text(top, " Error ", error_message); + } else { + print_server_state(top, engine); + } + + werase(cli); + box(cli, 0, 0); + mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + wrefresh(cli); + } + + endwin(); +} + +#endif // CAPIO_CL_UI_H diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index b48fd43..859668c 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -1,10 +1,7 @@ #include -#include #include #include -#include #include -#include #include "capiocl.hpp" @@ -33,203 +30,10 @@ std::vector split(const std::string &str, const char delimiter) { return result; } +#ifdef _INTERACTIVE_BUILDER +#include "capio_cl_builder.h" +#endif -// ----------------- Helper: capture std::cout ----------------- -class CaptureBuf : public std::stringbuf { - public: - std::string get_and_clear() { - std::string out = str(); - str(""); // clear - return out; - } -}; - -// ----------------- Helper: render ANSI text in ncurses ----------------- -void render_ansi_to_window(WINDOW *win, const std::string &text, int start_y, int start_x) { - static bool colors_init = false; - if (!colors_init) { - start_color(); - use_default_colors(); - init_pair(30, COLOR_BLACK, -1); - init_pair(31, COLOR_RED, -1); - init_pair(32, COLOR_GREEN, -1); - init_pair(33, COLOR_YELLOW, -1); - init_pair(34, COLOR_BLUE, -1); - init_pair(35, COLOR_MAGENTA, -1); - init_pair(36, COLOR_CYAN, -1); - init_pair(37, COLOR_WHITE, -1); - colors_init = true; - } - - int y = start_y; - int x = start_x; - int attr_on = 0; - - auto set_color = [&](int code) { - if (code == 0) { - if (attr_on != 0) { - wattroff(win, COLOR_PAIR(attr_on)); - attr_on = 0; - } - return; - } - if (code >= 30 && code <= 37) { - if (attr_on != 0) { - wattroff(win, COLOR_PAIR(attr_on)); - } - wattron(win, COLOR_PAIR(code)); - attr_on = code; - } - }; - - for (size_t i = 0; i < text.size();) { - if (i + 2 < text.size() && text[i] == '\x1b' && text[i + 1] == '[') { - size_t mpos = text.find('m', i + 2); - if (mpos == std::string::npos) { - break; - } - std::string seq = text.substr(i + 2, mpos - (i + 2)); - std::stringstream ss(seq); - std::string tok; - while (getline(ss, tok, ';')) { - if (!tok.empty()) { - set_color(std::atoi(tok.c_str())); - } - } - i = mpos + 1; - continue; - } - - if (text[i] == '\n') { - y++; - x = start_x; - int maxy, maxx; - getmaxyx(win, maxy, maxx); - if (y >= maxy - 1) { - wscrl(win, 1); - y = maxy - 2; - } - ++i; - continue; - } - - // Printable char - mvwaddch(win, y, x, text[i]); - ++x; - int maxy, maxx; - getmaxyx(win, maxy, maxx); - if (x >= maxx - 1) { - x = start_x; - y++; - if (y >= maxy - 1) { - wscrl(win, 1); - y = maxy - 2; - } - } - ++i; - } -} - -// ----------------- Main function ----------------- -void capio_cl_builder() { - initscr(); - cbreak(); - noecho(); - curs_set(1); - - int height, width; - getmaxyx(stdscr, height, width); - - // Stack windows vertically - int cli_height = 6; - int top_height = height - cli_height; - - WINDOW *top = newwin(top_height, width, 0, 0); - WINDOW *cli = newwin(cli_height, width, top_height, 0); - - scrollok(top, TRUE); - scrollok(cli, TRUE); - - box(top, 0, 0); - box(cli, 0, 0); - mvwprintw(top, 0, 2, " Engine Output "); - mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); - wrefresh(top); - wrefresh(cli); - - capiocl::Engine engine; - bool terminate = false; - char input[256]; - - while (!terminate) { - // Prompt in bottom window - werase(cli); - box(cli, 0, 0); - mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); - mvwprintw(cli, 2, 2, "command> "); - wmove(cli, 2, 11); - echo(); - wrefresh(cli); - - wgetnstr(cli, input, sizeof(input) - 1); - noecho(); - - std::string line(input); - auto args = split(line, ' '); - if (args.empty()) { - continue; - } - const std::string &command = args[0]; - - if (command == "exit") { - terminate = true; - } else if (command == "help") { - mvwprintw(cli, 4, 2, - "Commands:\n" - "\thelp - Show this menu\n" - "\texit - Quit CAPIO-CL builder\n" - "\tsave - Save workflow\n" - "\tadd - Add new file\n"); - } else if (command == "save") { - if (args.size() < 2) { - mvwprintw(cli, 4, 2, "Error: missing filename\n"); - } else { - capiocl::Serializer::dump(engine, "TODO:WORKFLOW_NAME", args[1]); - } - } else if (command == "add") { - if (args.size() < 2) { - mvwprintw(cli, 4, 2, "Error: missing filename\n"); - } else { - engine.newFile(args[1]); - } - } else { - mvwprintw(cli, 4, 2, "Unknown command: %s\n", command.c_str()); - } - - // Capture engine output and render with ANSI colors - CaptureBuf cap; - std::streambuf *old_buf = std::cout.rdbuf(&cap); - engine.print(); - std::cout.flush(); - std::cout.rdbuf(old_buf); - - std::string out = cap.get_and_clear(); - - werase(top); - box(top, 0, 0); - mvwprintw(top, 0, 2, " Engine Output "); - render_ansi_to_window(top, out, 1, 2); - wrefresh(top); - - // Clear CLI after each command - werase(cli); - box(cli, 0, 0); - mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); - wrefresh(cli); - } - - endwin(); -} int main(int argc, char **argv) { std::cout << capio_cl_header_help << std::endl; args::ArgumentParser parser( @@ -278,6 +82,11 @@ int main(int argc, char **argv) { } if (builder) { + +#ifdef _INTERACTIVE_BUILDER capio_cl_builder(); +#else + std::cout << "Interactive builder is not available!" << std::endl; +#endif } } \ No newline at end of file From 841e137ed0c6c6471f4a2577dd3ec9a926225b43 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Sun, 26 Oct 2025 16:27:58 +0100 Subject: [PATCH 06/10] fixes --- utilities/capio_cl_builder.h | 55 +++++++++++++++++++++++------------- utilities/capiocl-utils.cpp | 23 ++++++++------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h index c9d05c2..43005c5 100644 --- a/utilities/capio_cl_builder.h +++ b/utilities/capio_cl_builder.h @@ -36,6 +36,10 @@ constexpr char HELP_MESSAGE_COMMANDS[] = " set exclude Exclude from workflow output\n" " set directory Mark as directory\n" " set file Mark as regular file\n" + " set committed Set commit rule for file\n" + " set fire Set fire rule for file\n" + " set close Set number of close for commit_on_close:N\n" + " set nfiles Set number of files inside directory\n" "\n" "Unset Commands:\n" " unset permanent Remove 'permanent' flag from \n" @@ -54,42 +58,38 @@ class CaptureBuf : public std::stringbuf { return out; } }; -inline void render_ansi_to_window(WINDOW *win, const std::string &text, int start_y, int start_x) { + +inline void render_ansi_to_window(WINDOW *pad, const std::string &text, int start_y, int start_x) { // Regex to match ANSI escape sequences (like color codes) static const std::regex ansi_regex("\x1B\\[[0-9;?]*[ -/]*[@-~]"); static const std::regex remove_capio_cl_pre(R"(\[CAPIO-CL [^\]]*\])"); + static const std::regex remove_first_capiocl_row(".*Composition of expected CAPIO FS:.*\\n?"); std::string clean = std::regex_replace(text, ansi_regex, ""); - clean = std::regex_replace(clean, remove_capio_cl_pre, ""); + clean = std::regex_replace(clean, remove_capio_cl_pre, ""); + clean = std::regex_replace(clean, remove_first_capiocl_row, ""); int y = start_y; int x = start_x; - int maxy, maxx; - getmaxyx(win, maxy, maxx); for (char c : clean) { if (c == '\n') { y++; x = start_x; } else { - mvwaddch(win, y, x, c); + mvwaddch(pad, y, x, c); x++; } - // Handle wrapping and scrolling - if (x >= maxx - 1) { + // Let pad grow naturally; no wrapping limit + if (x >= 1000) { // arbitrary max pad width safety cap x = start_x; y++; } - if (y >= maxy - 1) { - wscrl(win, 1); - y = maxy - 2; - } } - - wrefresh(win); } + inline void print_top_text(WINDOW *top, const std::string &title, const std::string &text) { werase(top); box(top, 0, 0); @@ -192,6 +192,22 @@ inline std::tuple handle_set_command(std::vector } else if (target == "file") { const std::string &target_file = args[1]; engine.setFile(target_file); + } else if (target == "commit") { + const std::string &target_file = args[1]; + const std::string &rule = args[2]; + engine.setCommitRule(target_file, rule); + } else if (target == "fire") { + const std::string &target_file = args[1]; + const std::string &rule = args[2]; + engine.setFireRule(target_file, rule); + } else if (target == "close") { + const std::string &target_file = args[1]; + const auto &count = std::stoi(args[2]); + engine.setCommitedCloseNumber(target_file, count); + } else if (target == "nfiles") { + const std::string &target_file = args[1]; + const auto &count = std::stoi(args[2]); + engine.setDirectoryFileCount(target_file, count); } else { error_message = "Unknown subcommand for set: " + args[1]; error_occurred = true; @@ -262,12 +278,13 @@ inline void capio_cl_builder() { capiocl::Engine &)> command_handlers; - command_handlers["add"] = &handle_add_command; - command_handlers["save"] = &handle_save_command; - command_handlers["print"] = &handle_print_command; - command_handlers["help"] = &handle_help_command; - command_handlers["set"] = &handle_set_command; - command_handlers["unset"] = &handle_unset_command; + command_handlers["add"] = &handle_add_command; + command_handlers["save"] = &handle_save_command; + command_handlers["print"] = &handle_print_command; + command_handlers["help"] = &handle_help_command; + command_handlers["set"] = &handle_set_command; + command_handlers["unset"] = &handle_unset_command; + command_handlers["delete"] = &handle_delete_command; while (!terminate) { diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index 859668c..febf4ca 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -35,7 +35,7 @@ std::vector split(const std::string &str, const char delimiter) { #endif int main(int argc, char **argv) { - std::cout << capio_cl_header_help << std::endl; + args::ArgumentParser parser( "CAPIO-CL Utilities", "Developed by Marco Edoardo Santimaria \n marcoedoardo.santimaria@unito.it"); @@ -60,6 +60,18 @@ int main(int argc, char **argv) { return 1; } + if (builder) { + +#ifdef _INTERACTIVE_BUILDER + capio_cl_builder(); + exit(EXIT_SUCCESS); +#else + std::cout << "Interactive builder is not available!" << std::endl; +#endif + } + + std::cout << capio_cl_header_help << std::endl; + if (validate) { const std::string path = args::get(validate); try { @@ -80,13 +92,4 @@ int main(int argc, char **argv) { << std::endl; return 0; } - - if (builder) { - -#ifdef _INTERACTIVE_BUILDER - capio_cl_builder(); -#else - std::cout << "Interactive builder is not available!" << std::endl; -#endif - } } \ No newline at end of file From 67f1c6c0ac383292691a97db85aa42d5d1ba4216 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Mon, 27 Oct 2025 10:40:22 +0100 Subject: [PATCH 07/10] Improved builder --- capiocl.hpp | 1 - src/Engine.cpp | 7 ++ utilities/capio_cl_builder.h | 146 ++++++++++++++++++++++++++++++----- 3 files changed, 132 insertions(+), 22 deletions(-) diff --git a/capiocl.hpp b/capiocl.hpp index 078366b..6dc156f 100644 --- a/capiocl.hpp +++ b/capiocl.hpp @@ -96,7 +96,6 @@ struct defaults; namespace webapi { class CapioClWebApiServer; } - } // namespace capiocl #endif // CAPIO_CL_CAPIOCL_HPP \ No newline at end of file diff --git a/src/Engine.cpp b/src/Engine.cpp index d6a37c2..69ae0b2 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -243,6 +243,13 @@ long capiocl::engine::Engine::getDirectoryFileCount(const std::filesystem::path this->_newFile(path); return getDirectoryFileCount(path); } +std::vector capiocl::Engine::getFiles() const { + std::vector files; + for (const auto &[fst, snd] : _capio_cl_entries) { + files.push_back(fst); + } + return files; +} void capiocl::engine::Engine::addProducer(const std::filesystem::path &path, std::string &producer) { diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h index 43005c5..0a9d098 100644 --- a/utilities/capio_cl_builder.h +++ b/utilities/capio_cl_builder.h @@ -50,15 +50,6 @@ constexpr char HELP_MESSAGE_COMMANDS[] = "\n" "=====================================================================\n"; -class CaptureBuf : public std::stringbuf { - public: - std::string get_and_clear() { - std::string out = str(); - str(""); // clear - return out; - } -}; - inline void render_ansi_to_window(WINDOW *pad, const std::string &text, int start_y, int start_x) { // Regex to match ANSI escape sequences (like color codes) static const std::regex ansi_regex("\x1B\\[[0-9;?]*[ -/]*[@-~]"); @@ -89,7 +80,6 @@ inline void render_ansi_to_window(WINDOW *pad, const std::string &text, int star } } - inline void print_top_text(WINDOW *top, const std::string &title, const std::string &text) { werase(top); box(top, 0, 0); @@ -101,15 +91,6 @@ inline void print_top_text(WINDOW *top, const std::string &title, const std::str doupdate(); } -inline void print_server_state(WINDOW *top, capiocl::Engine engine) { - CaptureBuf cap; - std::streambuf *old_buf = std::cout.rdbuf(&cap); - engine.print(); - std::cout.flush(); - std::cout.rdbuf(old_buf); - print_top_text(top, " Engine Output ", cap.get_and_clear()); -} - inline std::tuple handle_add_command(std::vector &args, capiocl::Engine &engine) { const std::string &add_type = args[0]; @@ -242,6 +223,129 @@ inline std::tuple handle_delete_command(std::vector headers = {"File", "Producers", "Consumers", "Stored", "Commit", + "Fire", "Excluded", "Permanent", "N_files"}; + + std::vector min_widths = {12, 18, 18, 18, 10, 7, 9, 10, 8}; + std::vector dynamic_cols = {0}; + + int total_fixed = 0; + for (size_t i = 0; i < headers.size(); ++i) { + if (std::find(dynamic_cols.begin(), dynamic_cols.end(), i) == dynamic_cols.end()) { + total_fixed += min_widths[i] + 1; + } + } + + // dynamic columns + int available = std::max(0, win_width - 4 - total_fixed); // borders & padding + int base_dynamic = 0; + for (auto idx : dynamic_cols) { + base_dynamic += min_widths[idx]; + } + + int extra_per_col = available > base_dynamic ? available - base_dynamic : 0; + int extra_each = extra_per_col / (int) dynamic_cols.size(); + + std::vector col_widths = min_widths; + for (auto idx : dynamic_cols) { + col_widths[idx] += extra_each; + } + + struct Row { + std::string file, stored, producers, consumers, commit, fire; + bool excluded, permanent; + long nfiles; + }; + + std::vector rows; + + for (const auto &file : engine.getFiles()) { + Row row; + row.file = file; + row.stored = engine.isStoredInMemory(file) ? "MEM" : "FS"; + + std::ostringstream prod, cons; + for (auto &p : engine.getProducers(file)) { + prod << p << " "; + } + for (auto &c : engine.getConsumers(file)) { + cons << c << " "; + } + row.producers = prod.str(); + row.consumers = cons.str(); + + row.commit = engine.getCommitRule(file); + row.fire = engine.getFireRule(file); + row.excluded = engine.isExcluded(file); + row.permanent = engine.isPermanent(file); + row.nfiles = engine.getCommitCloseCount(file); + + rows.push_back(row); + } + + int y = 1; + int x = 2; + + // ---- HEADER ---- + wattron(top, A_BOLD | A_REVERSE); + for (size_t i = 0; i < headers.size(); ++i) { + mvwprintw(top, y, x, "%-*.*s", col_widths[i], col_widths[i], headers[i].c_str()); + x += col_widths[i] + 1; + } + wattroff(top, A_BOLD | A_REVERSE); + + y++; + + // ---- ROWS ---- + int visible_rows = win_height - 3; + int row_idx = 0; + for (auto &r : rows) { + if (y >= win_height - 1) { + break; + } + + if (row_idx % 2 == 0) { + wattron(top, A_DIM); + } else { + wattroff(top, A_DIM); + } + + x = 2; + std::vector values = {r.file, + r.producers, + r.consumers, + r.commit, + r.fire, + r.stored, + r.excluded ? "yes" : "no", + r.permanent ? "yes" : "no", + std::to_string(r.nfiles)}; + + for (size_t i = 0; i < values.size(); ++i) { + std::string v = values[i]; + if ((int) v.size() > col_widths[i]) { + v = v.substr(0, col_widths[i] - 1) + "…"; + } + mvwprintw(top, y, x, "%-*.*s", col_widths[i], col_widths[i], v.c_str()); + x += col_widths[i] + 1; + } + + y++; + row_idx++; + } + + wattroff(top, A_DIM); + wrefresh(top); +} + inline void capio_cl_builder() { initscr(); cbreak(); @@ -272,7 +376,7 @@ inline void capio_cl_builder() { bool terminate = false; char input[256]; - print_server_state(top, engine); + draw_engine_table(top, engine); std::unordered_map (*)(std::vector &, capiocl::Engine &)> @@ -327,7 +431,7 @@ inline void capio_cl_builder() { error_message += HELP_MESSAGE_COMMANDS; print_top_text(top, " Error ", error_message); } else { - print_server_state(top, engine); + draw_engine_table(top, engine); } werase(cli); From 48f3556006c4c70233f24705e2fc9ba165f2322d Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Mon, 27 Oct 2025 22:01:06 +0100 Subject: [PATCH 08/10] UI improv --- utilities/capio_cl_builder.h | 34 +++++++++++++++++++--------------- utilities/capiocl-utils.cpp | 2 +- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h index 0a9d098..663edf5 100644 --- a/utilities/capio_cl_builder.h +++ b/utilities/capio_cl_builder.h @@ -231,8 +231,8 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { int win_height, win_width; getmaxyx(top, win_height, win_width); - std::vector headers = {"File", "Producers", "Consumers", "Stored", "Commit", - "Fire", "Excluded", "Permanent", "N_files"}; + std::vector headers = {"File", "Producers", "Consumers", "Commit", "Fire", + "Store", "Excluded", "Permanent", "N_files"}; std::vector min_widths = {12, 18, 18, 18, 10, 7, 9, 10, 8}; std::vector dynamic_cols = {0}; @@ -295,28 +295,25 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { int x = 2; // ---- HEADER ---- - wattron(top, A_BOLD | A_REVERSE); + wattron(top, COLOR_PAIR(1) | A_BOLD); for (size_t i = 0; i < headers.size(); ++i) { mvwprintw(top, y, x, "%-*.*s", col_widths[i], col_widths[i], headers[i].c_str()); x += col_widths[i] + 1; } - wattroff(top, A_BOLD | A_REVERSE); + wattroff(top, COLOR_PAIR(1) | A_BOLD); y++; // ---- ROWS ---- - int visible_rows = win_height - 3; - int row_idx = 0; + int row_idx = 0; for (auto &r : rows) { if (y >= win_height - 1) { break; } - if (row_idx % 2 == 0) { - wattron(top, A_DIM); - } else { - wattroff(top, A_DIM); - } + // Alternate background colors + int pair_id = (row_idx % 2 == 0) ? 2 : 3; + wattron(top, COLOR_PAIR(pair_id)); x = 2; std::vector values = {r.file, @@ -338,6 +335,7 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { x += col_widths[i] + 1; } + wattroff(top, COLOR_PAIR(pair_id)); y++; row_idx++; } @@ -348,10 +346,16 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { inline void capio_cl_builder() { initscr(); + start_color(); + use_default_colors(); cbreak(); noecho(); curs_set(1); + init_pair(1, COLOR_WHITE, COLOR_BLACK); + init_pair(2, COLOR_YELLOW, COLOR_BLACK); + init_pair(3, COLOR_RED, COLOR_BLACK); + int height, width; getmaxyx(stdscr, height, width); @@ -368,7 +372,7 @@ inline void capio_cl_builder() { box(top, 0, 0); box(cli, 0, 0); mvwprintw(top, 0, 2, " Engine Output "); - mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); + mvwprintw(cli, 0, 2, " Command interface "); wrefresh(top); wrefresh(cli); @@ -397,9 +401,9 @@ inline void capio_cl_builder() { werase(cli); box(cli, 0, 0); - mvwprintw(cli, 0, 2, " CAPIO-CL Builder "); - mvwprintw(cli, 2, 2, "command> "); - wmove(cli, 2, 11); + mvwprintw(cli, 0, 2, " Command "); + mvwprintw(cli, 2, 2, "> "); + wmove(cli, 2, 4); echo(); wrefresh(cli); diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index febf4ca..8b1f813 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -75,7 +75,7 @@ int main(int argc, char **argv) { if (validate) { const std::string path = args::get(validate); try { - auto parsed = capiocl::Parser::parse(path); + capiocl::Parser::parse(path); } catch (...) { std::cerr << std::endl << "\t+==================================================+\n" From 420a6c29a4fe9f1d2b4d3f041241e6349e603d05 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Thu, 30 Oct 2025 14:19:25 +0100 Subject: [PATCH 09/10] Fixed bug on save command --- utilities/capio_cl_builder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h index 663edf5..711ab19 100644 --- a/utilities/capio_cl_builder.h +++ b/utilities/capio_cl_builder.h @@ -124,11 +124,11 @@ inline std::tuple handle_save_command(std::vector Date: Sat, 31 Jan 2026 19:04:36 +0000 Subject: [PATCH 10/10] Updated --- CMakeLists.txt | 5 +++++ src/Engine.cpp | 7 ------- utilities/capio_cl_builder.h | 33 ++++++++++++++++++--------------- utilities/capiocl-utils.cpp | 4 +++- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b21ae2..41d5105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,12 +195,17 @@ if (BUILD_UTILS) ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src ${jsoncons_SOURCE_DIR}/include + ${TOMLPLUSPLUS_SOURCE_DIR}/include ${CAPIOCL_JSON_SCHEMAS_DIRECTORY} ${args_SOURCE_DIR} ${CURSES_INCLUDE_DIR} ) target_link_libraries(capiocl_utils PUBLIC ${CURSES_LIBRARIES}) + target_link_libraries(capiocl_utils PRIVATE + tomlplusplus::tomlplusplus + httplib::httplib + ) endif (BUILD_UTILS) ##################################### diff --git a/src/Engine.cpp b/src/Engine.cpp index 69ae0b2..d6a37c2 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -243,13 +243,6 @@ long capiocl::engine::Engine::getDirectoryFileCount(const std::filesystem::path this->_newFile(path); return getDirectoryFileCount(path); } -std::vector capiocl::Engine::getFiles() const { - std::vector files; - for (const auto &[fst, snd] : _capio_cl_entries) { - files.push_back(fst); - } - return files; -} void capiocl::engine::Engine::addProducer(const std::filesystem::path &path, std::string &producer) { diff --git a/utilities/capio_cl_builder.h b/utilities/capio_cl_builder.h index 711ab19..35136b2 100644 --- a/utilities/capio_cl_builder.h +++ b/utilities/capio_cl_builder.h @@ -10,6 +10,9 @@ #include #include +#include "capiocl.hpp" +#include "capiocl/engine.h" + constexpr char HELP_MESSAGE_COMMANDS[] = "\n" "=====================================================================\n" @@ -36,7 +39,7 @@ constexpr char HELP_MESSAGE_COMMANDS[] = " set exclude Exclude from workflow output\n" " set directory Mark as directory\n" " set file Mark as regular file\n" - " set committed Set commit rule for file\n" + " set commit Set commit rule for file\n" " set fire Set fire rule for file\n" " set close Set number of close for commit_on_close:N\n" " set nfiles Set number of files inside directory\n" @@ -92,7 +95,7 @@ inline void print_top_text(WINDOW *top, const std::string &title, const std::str } inline std::tuple handle_add_command(std::vector &args, - capiocl::Engine &engine) { + capiocl::engine::Engine &engine) { const std::string &add_type = args[0]; std::string error_message; bool error_occurred = false; @@ -120,7 +123,7 @@ inline std::tuple handle_add_command(std::vector } inline std::tuple handle_save_command(std::vector &args, - capiocl::Engine &engine) { + capiocl::engine::Engine &engine) { std::string error_message; bool error_occurred = false; @@ -128,25 +131,25 @@ inline std::tuple handle_save_command(std::vector handle_print_command([[maybe_unused]] std::vector &args, - [[maybe_unused]] capiocl::Engine &engine) { + [[maybe_unused]] capiocl::engine::Engine &engine) { return {false, ""}; } inline std::tuple handle_help_command([[maybe_unused]] std::vector &args, - [[maybe_unused]] capiocl::Engine &engine) { + [[maybe_unused]] capiocl::engine::Engine &engine) { return {true, ""}; } inline std::tuple handle_set_command(std::vector &args, - capiocl::Engine &engine) { + capiocl::engine::Engine &engine) { std::string error_message; bool error_occurred = false; @@ -197,7 +200,7 @@ inline std::tuple handle_set_command(std::vector } inline std::tuple handle_unset_command(std::vector &args, - capiocl::Engine &engine) { + capiocl::engine::Engine &engine) { std::string error_message; bool error_occurred = false; @@ -216,14 +219,14 @@ inline std::tuple handle_unset_command(std::vector handle_delete_command(std::vector &args, - capiocl::Engine &engine) { + capiocl::engine::Engine &engine) { const std::string &file = args[0]; engine.remove(file); return {false, ""}; } -inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { +inline void draw_engine_table(WINDOW *top, const capiocl::engine::Engine &engine) { werase(top); box(top, 0, 0); mvwprintw(top, 0, 2, " CAPIO-CL Engine State "); @@ -231,7 +234,7 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { int win_height, win_width; getmaxyx(top, win_height, win_width); - std::vector headers = {"File", "Producers", "Consumers", "Commit", "Fire", + std::vector headers = {"File", "Producers", "Consumers", "Commit", "Fire", "Store", "Excluded", "Permanent", "N_files"}; std::vector min_widths = {12, 18, 18, 18, 10, 7, 9, 10, 8}; @@ -267,7 +270,7 @@ inline void draw_engine_table(WINDOW *top, const capiocl::Engine &engine) { std::vector rows; - for (const auto &file : engine.getFiles()) { + for (const auto &file : engine.getPaths()) { Row row; row.file = file; row.stored = engine.isStoredInMemory(file) ? "MEM" : "FS"; @@ -360,7 +363,7 @@ inline void capio_cl_builder() { getmaxyx(stdscr, height, width); // Stack vertically - int cli_height = 10; + int cli_height = 4; int top_height = height - cli_height; WINDOW *top = newwin(top_height, width, 0, 0); @@ -376,14 +379,14 @@ inline void capio_cl_builder() { wrefresh(top); wrefresh(cli); - capiocl::Engine engine; + capiocl::engine::Engine engine; bool terminate = false; char input[256]; draw_engine_table(top, engine); std::unordered_map (*)(std::vector &, - capiocl::Engine &)> + capiocl::engine::Engine &)> command_handlers; command_handlers["add"] = &handle_add_command; diff --git a/utilities/capiocl-utils.cpp b/utilities/capiocl-utils.cpp index 8b1f813..d2ee84c 100644 --- a/utilities/capiocl-utils.cpp +++ b/utilities/capiocl-utils.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include "capiocl.hpp" +#include "capiocl/parser.h" constexpr char capio_cl_header_help[] = R"( ______ ______ _______ ______ ______ ______ __ @@ -75,7 +77,7 @@ int main(int argc, char **argv) { if (validate) { const std::string path = args::get(validate); try { - capiocl::Parser::parse(path); + capiocl::parser::Parser::parse(path); } catch (...) { std::cerr << std::endl << "\t+==================================================+\n"