tui: add --batch mode to run a script and print output headless

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 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 15:36:41 +02:00
parent 952afe3979
commit 7cec6e1b0c
3 changed files with 24 additions and 1 deletions

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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`).