From 7cec6e1b0c64b474ad107bf3c7155865b39e7e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Wed, 3 Jun 2026 15:36:41 +0200 Subject: [PATCH] tui: add --batch mode to run a script and print output headless MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BootDispatch already runs --restore/--source synchronously before the TUI starts (Source takes its headless drain branch when no screen is attached), so the console buffer is complete by then. New --batch flag dumps that buffer (Tui::DumpOutput) to stdout and exits without launching the TUI — enabling scripted/CI runs and verify output capture (e.g. essim --batch --source s). Co-Authored-By: Claude Opus 4.8 --- src/main.cpp | 17 ++++++++++++++++- src/tui/shell.cpp | 5 +++++ src/tui/tui.hpp | 3 +++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index a0afa1c..f288cdd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ namespace { void print_usage(const char *prog) { std::cerr << - "usage: " << prog << " [--source FILE] [--restore FILE]\n" + "usage: " << prog << " [--batch] [--source FILE] [--restore FILE]\n" " " << prog << " --commands-md [FILE]\n" " " << prog << " --help\n" " (no args) launch the TUI on an empty system.\n" @@ -19,6 +19,8 @@ void print_usage(const char *prog) { " FILE (same as the `restore` command).\n" " Combine with --source to layer a script on\n" " top of a restored snapshot.\n" + " --batch run --restore/--source, print the console\n" + " output to stdout, and exit without the TUI.\n" " --commands-md [FILE] dump the command registry as Markdown.\n" " With FILE: write there. Without: stdout.\n" " (Used by `cmake --build build --target doc`.)\n" @@ -30,6 +32,7 @@ void print_usage(const char *prog) { int main(int argc, char **argv) { std::string boot_restore; std::string boot_source; + bool batch = false; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; @@ -63,6 +66,10 @@ int main(int argc, char **argv) { boot_restore = argv[++i]; continue; } + if (a == "--batch") { + batch = true; + continue; + } if (a == "--help" || a == "-h") { print_usage(argv[0]); return 0; @@ -78,6 +85,14 @@ int main(int argc, char **argv) { // snapshot, then re-run a small script that adds a new card"). if (!boot_restore.empty()) tui.BootDispatch("restore " + boot_restore); if (!boot_source.empty()) tui.BootDispatch("source " + boot_source); + + // Batch mode: the boot dispatch already ran synchronously (no screen yet), + // so the console output is complete. Print it and exit without the TUI. + if (batch) { + tui.DumpOutput(std::cout); + return 0; + } + tui.Run(); return 0; } diff --git a/src/tui/shell.cpp b/src/tui/shell.cpp index 6c52002..8601da4 100644 --- a/src/tui/shell.cpp +++ b/src/tui/shell.cpp @@ -36,6 +36,11 @@ void Tui::Print(const std::string &line) { scroll_offset = 0; // any new line snaps the view back to the tail } +void Tui::DumpOutput(std::ostream &out) const { + for (const std::string &line : output) + out << line << "\n"; +} + void Tui::HistoryUp() { if (history.empty()) return; if (history_idx == -1) history_idx = (int)history.size() - 1; diff --git a/src/tui/tui.hpp b/src/tui/tui.hpp index b61c428..53abd45 100644 --- a/src/tui/tui.hpp +++ b/src/tui/tui.hpp @@ -197,6 +197,9 @@ public: ~Tui(); void Run(); void DumpCommandsMd(std::ostream &out) const; + // Write the accumulated console output to `out`. Used by batch mode to + // surface a script's output without starting the TUI. + void DumpOutput(std::ostream &out) const; // Boot-time hook: dispatch a single command exactly as if the user // typed it (e.g. `restore foo.essim` or `source bring-up.essim`).