tui: global script progress + dashboard source/restore work

Opening a script from the dashboard did nothing visually: the tick driving the
line-by-line loader was only handled in the console case, and the Computing…
overlay was console-only. Move both to the global layer — ticks now process on
any screen (the dashboard updates live as the script loads) and the Computing…
box overlays whatever screen is active. Add an 'r' dashboard shortcut to
restore a snapshot via the file picker (open mode, like 'o'). Dashboard help
hints (loaded + empty state) updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 19:02:13 +02:00
parent c70e767cf1
commit 29cb353d75
3 changed files with 38 additions and 16 deletions

View File

@@ -45,6 +45,7 @@ Component Tui::BuildDashboardScreen() {
Element early_help = RenderHelpPanel("dashboard", { Element early_help = RenderHelpPanel("dashboard", {
{"c", "console"}, {"c", "console"},
{"o", "open/run a script"}, {"o", "open/run a script"},
{"r", "restore a snapshot"},
{"a", "analyze"}, {"a", "analyze"},
{"h", "help screen"}, {"h", "help screen"},
{"q", "quit"}, {"q", "quit"},
@@ -57,8 +58,8 @@ Component Tui::BuildDashboardScreen() {
separator(), separator(),
hbox({ hbox({
vbox({ vbox({
text(" no system loaded — run 'new' or 'restore <file>'") | dim, text(" no system loaded") | dim,
text(" (press 'o' to open a script, 'c' for the console, Ctrl-P for the palette)") | dim, text(" (press 'o' open a script · 'r' restore a snapshot · 'c' console · Ctrl-P palette)") | dim,
filler(), filler(),
}) | flex, }) | flex,
separator(), separator(),
@@ -312,6 +313,7 @@ Component Tui::BuildDashboardScreen() {
{"x", "export"}, {"x", "export"},
{"o", "open/run a script"}, {"o", "open/run a script"},
{"s", "save system"}, {"s", "save system"},
{"r", "restore a snapshot"},
{"PgUp", "scroll up"}, {"PgUp", "scroll up"},
{"PgDn", "scroll down"}, {"PgDn", "scroll down"},
{"Home", "scroll top"}, {"Home", "scroll top"},

View File

@@ -89,18 +89,8 @@ Component Tui::BuildMainScreen(ScreenInteractive &screen) {
}) | flex, }) | flex,
}) | border; }) | border;
if (loading) { // The "Computing…" overlay is rendered globally in Run(), so it shows
int total = (int)loading_lines.size(); // on whatever screen is active while a script loads.
std::string progress = std::to_string(loading_executed) + " / "
+ std::to_string(total) + " lines";
auto modal = vbox({
text(" Computing… ") | bold | center,
separator(),
text(loading_filename) | center,
text(progress) | center,
}) | borderDouble | size(WIDTH, GREATER_THAN, 40);
return dbox({base, modal | center});
}
return base; return base;
}); });
} }

View File

@@ -5,6 +5,7 @@
#include <ftxui/component/component.hpp> #include <ftxui/component/component.hpp>
#include <ftxui/component/event.hpp> #include <ftxui/component/event.hpp>
#include <ftxui/component/screen_interactive.hpp> #include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
using namespace ftxui; using namespace ftxui;
@@ -58,7 +59,28 @@ void Tui::Run() {
auto with_error = with_confirm auto with_error = with_confirm
| Modal(BuildErrorModal(), &error_open); | Modal(BuildErrorModal(), &error_open);
auto root = CatchEvent(with_error, [this](Event e) { // Global "Computing…" overlay while a script loads — visible on any screen
// (not just the console), so opening a script from the dashboard shows
// progress instead of looking frozen.
auto with_loading = Renderer(with_error, [this, with_error] {
Element base = with_error->Render();
if (!loading) return base;
std::string progress = std::to_string(loading_executed) + " / "
+ std::to_string((int)loading_lines.size()) + " lines";
Element modal = vbox({
text(" Computing… ") | bold | center,
separator(),
text(loading_filename) | center,
text(progress) | center,
}) | borderDouble | size(WIDTH, GREATER_THAN, 40);
return dbox({base, modal | center});
});
auto root = CatchEvent(with_loading, [this](Event e) {
// Source ticks drive the line-by-line loader; handle them on ANY screen
// so `source` works from the dashboard, not only the console.
if (e == Event::Special("\x02tick")) { ProcessNextSourceLine(); return true; }
// Modals own their events while open. Error modal sits on top. // Modals own their events while open. Error modal sits on top.
if (error_open || confirm_open || palette_open if (error_open || confirm_open || palette_open
|| sigtype_dialog_open || file_dialog.open) return false; || sigtype_dialog_open || file_dialog.open) return false;
@@ -119,6 +141,15 @@ void Tui::Run() {
}); });
return true; return true;
} }
if (e == Event::Character("r")) { // restore a saved system
OpenFileDialog("Restore system — load a snapshot",
"dashboard.restore", "", {},
[this](const std::string &path) {
Dispatch("restore " + path);
},
/*confirm_overwrite=*/false); // opening, not saving
return true;
}
return false; return false;
case 3: // explore case 3: // explore
@@ -153,7 +184,6 @@ void Tui::Run() {
return false; return false;
default: // 0: main (console / log view) default: // 0: main (console / log view)
if (e == Event::Special("\x02tick")) { ProcessNextSourceLine(); return true; }
if (e == Event::Escape) { if (e == Event::Escape) {
if (!pending.empty()) { CancelPending(); return true; } if (!pending.empty()) { CancelPending(); return true; }
screen_idx = 4; return true; screen_idx = 4; return true;