From c8183241c3a0c2000aad31e8cc11e6585247ba09 Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 9 Jun 2026 19:37:48 -0500 Subject: [PATCH] feat(node): show a live daemon console tail on the initializing overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full-node Console tab already streams the daemon's output, but during startup the user is held on the loading overlay (wallet-data tabs are blocked), so they can't watch progress without navigating away. Surface the last few console lines the node printed (UpdateTip height=…, "Verifying blocks…", etc.) directly under the status/description on the overlay while initializing or warming up, so progress is visible where the user is already looking. Full-node only (guarded on daemon_controller_); each line is trimmed and ellipsis-truncated to one row. Reuses DaemonController::recentLines(). Co-Authored-By: Claude Opus 4.8 --- src/app.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/app.cpp b/src/app.cpp index bd4bdf8..cf12938 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -3318,6 +3318,41 @@ void App::renderLoadingOverlay(float contentH) curY += ts.y + gap; } + // ------------------------------------------------------------------- + // 2c. Live daemon console tail (init/warmup only) — show the last few lines the node + // printed so the user can watch real progress (UpdateTip height=…, Verifying blocks…) + // without leaving the blocked overlay. Full-node only (lite has no daemon_controller_). + // ------------------------------------------------------------------- + if ((state_.daemon_initializing || state_.warming_up) && daemon_controller_) { + const auto lines = daemon_controller_->recentLines(4); + if (!lines.empty()) { + ImFont* logFont = Type().caption(); + if (!logFont) logFont = ImGui::GetFont(); + const float blockW = std::min(ws.x * 0.8f, 560.0f); + const ImU32 logCol = IM_COL32(140, 150, 165, 150); + curY += gap * 0.5f; + for (const auto& raw : lines) { + // Trim trailing CR/whitespace; skip blanks. + std::string line = raw; + while (!line.empty() && (line.back() == '\r' || line.back() == '\n' || + line.back() == ' ' || line.back() == '\t')) + line.pop_back(); + if (line.empty()) continue; + // Truncate (with an ellipsis) to keep each line on one row within blockW. + if (logFont->CalcTextSizeA(logFont->LegacySize, FLT_MAX, 0.0f, line.c_str()).x > blockW) { + while (line.size() > 1 && + logFont->CalcTextSizeA(logFont->LegacySize, FLT_MAX, 0.0f, (line + "…").c_str()).x > blockW) + line.pop_back(); + line += "…"; + } + dl->AddText(logFont, logFont->LegacySize, + ImVec2(wp.x + cx - blockW * 0.5f, curY), logCol, line.c_str()); + curY += logFont->LegacySize + 2.0f; + } + curY += gap; + } + } + // ------------------------------------------------------------------- // 3. Sync progress bar (if connected and syncing) // -------------------------------------------------------------------