refactor(console): phase 2 — channel-as-semantic key; decouple executor from UI colors

Make ConsoleChannel the canonical semantic classification of every console
line. Producers (command executor, app log forwarders, result formatter) tag
each line with a channel; the UI derives both the text color and the left
accent-bar color from it at draw time, and the output filter keys off it.

This replaces the prior scheme of storing an ImU32 color per line and then
reverse-engineering the source from color-equality plus a "[daemon] "/"[xmrig] "
/"[app] "/"[rpc] " text prefix. Consequences:

- ConsoleLine now stores {text, ConsoleChannel} — no per-line color.
- addLine()/addRpcTraceLine() take a channel; the redundant text prefixes are
  gone (the accent bar carries the origin).
- The executor's ConsoleAddLineFn hands a channel, not an ImU32, so the backend
  no longer depends on ConsoleTab::COLOR_* — FullNode/Lite executors emit clean
  text + channel.
- The theme-remap loop that rewrote stored colors on light/dark flip is deleted;
  colors are resolved per-channel each frame (refreshColors on flip only).
- ConsoleOutputFilter drops its color fields; consoleLinePassesFilter() keys off
  the channel. Test updated to the channel-based API.
- Added a Warning channel (amber severity peer of Error/Success) so the
  notification + logger warning forwarders keep their color.

Full-node + lite build clean; ctest green; source hygiene clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 18:22:35 -05:00
parent 19e83eb12a
commit 33735b1d52
9 changed files with 219 additions and 175 deletions

View File

@@ -3,7 +3,7 @@
// Released under the GPLv3
#include "console_command_executor.h"
#include "console_tab.h" // ConsoleTab::COLOR_* statics
#include "console_channel.h"
#include "console_input_model.h" // BuildConsoleRpcCall
#include "../../app.h"
@@ -103,17 +103,17 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
const DState cur = d->getState();
const int prev = last_daemon_state_;
if (cur == DState::Starting && prev == static_cast<int>(DState::Stopped)) {
add("", ConsoleTab::COLOR_RESULT);
add(TR("console_starting_node"), ConsoleTab::COLOR_INFO);
add(TR("console_capturing_output"), ConsoleTab::COLOR_INFO);
add("", ConsoleTab::COLOR_RESULT);
add("", ConsoleChannel::None);
add(TR("console_starting_node"), ConsoleChannel::Info);
add(TR("console_capturing_output"), ConsoleChannel::Info);
add("", ConsoleChannel::None);
} else if (cur == DState::Running && prev != static_cast<int>(DState::Running)) {
add(TR("console_daemon_started"), ConsoleTab::COLOR_INFO);
add(TR("console_daemon_started"), ConsoleChannel::Info);
} else if (cur == DState::Stopped && prev == static_cast<int>(DState::Running)) {
add("", ConsoleTab::COLOR_RESULT);
add(TR("console_daemon_stopped"), ConsoleTab::COLOR_INFO);
add("", ConsoleChannel::None);
add(TR("console_daemon_stopped"), ConsoleChannel::Info);
} else if (cur == DState::Error) {
add(std::string(TR("console_daemon_error")) + d->getLastError() + " ===", ConsoleTab::COLOR_ERROR);
add(std::string(TR("console_daemon_error")) + d->getLastError() + " ===", ConsoleChannel::Error);
}
last_daemon_state_ = static_cast<int>(cur);
}
@@ -121,8 +121,8 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
rpc::RPCClient* rpc = app_->consoleRpc();
if (rpc) {
const bool now = rpc->isConnected();
if (now && !last_rpc_connected_) add(TR("console_connected"), ConsoleTab::COLOR_INFO);
else if (!now && last_rpc_connected_) add(TR("console_disconnected"), ConsoleTab::COLOR_ERROR);
if (now && !last_rpc_connected_) add(TR("console_connected"), ConsoleChannel::Info);
else if (!now && last_rpc_connected_) add(TR("console_disconnected"), ConsoleChannel::Error);
last_rpc_connected_ = now;
}
@@ -133,12 +133,12 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
std::string line;
while (std::getline(ss, line)) {
if (line.empty()) continue;
ImU32 c = ConsoleTab::COLOR_DAEMON;
ConsoleChannel c = ConsoleChannel::Daemon;
if (line.find("[ERROR]") != std::string::npos ||
line.find("error:") != std::string::npos ||
line.find("Error:") != std::string::npos)
c = ConsoleTab::COLOR_ERROR;
add("[daemon] " + line, c);
c = ConsoleChannel::Error;
add(line, c); // channel conveys the source; no "[daemon] " prefix
}
}
}
@@ -151,14 +151,14 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
std::string line;
while (std::getline(ss, line)) {
if (line.empty()) continue;
ImU32 c = ConsoleTab::COLOR_DAEMON;
ConsoleChannel c = ConsoleChannel::Xmrig;
if (line.find("error") != std::string::npos ||
line.find("ERROR") != std::string::npos ||
line.find("failed") != std::string::npos)
c = ConsoleTab::COLOR_ERROR;
c = ConsoleChannel::Error;
else if (line.find("accepted") != std::string::npos)
c = ConsoleTab::COLOR_INFO;
add("[xmrig] " + line, c);
c = ConsoleChannel::Success;
add(line, c); // channel conveys the source; no "[xmrig] " prefix
}
}
} else {
@@ -168,22 +168,22 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
void FullNodeConsoleExecutor::printHelp(const ConsoleAddLineFn& add)
{
add(TR("console_available_commands"), ConsoleTab::COLOR_INFO);
add(TR("console_help_clear"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_help"), ConsoleTab::COLOR_RESULT);
add("", ConsoleTab::COLOR_RESULT);
add(TR("console_common_rpc"), ConsoleTab::COLOR_INFO);
add(TR("console_help_getinfo"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_getbalance"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_gettotalbalance"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_getblockcount"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_getpeerinfo"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_setgenerate"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_getmininginfo"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_stop"), ConsoleTab::COLOR_RESULT);
add("", ConsoleTab::COLOR_RESULT);
add(TR("console_click_commands"), ConsoleTab::COLOR_INFO);
add(TR("console_tab_completion"), ConsoleTab::COLOR_INFO);
add(TR("console_available_commands"), ConsoleChannel::Info);
add(TR("console_help_clear"), ConsoleChannel::None);
add(TR("console_help_help"), ConsoleChannel::None);
add("", ConsoleChannel::None);
add(TR("console_common_rpc"), ConsoleChannel::Info);
add(TR("console_help_getinfo"), ConsoleChannel::None);
add(TR("console_help_getbalance"), ConsoleChannel::None);
add(TR("console_help_gettotalbalance"), ConsoleChannel::None);
add(TR("console_help_getblockcount"), ConsoleChannel::None);
add(TR("console_help_getpeerinfo"), ConsoleChannel::None);
add(TR("console_help_setgenerate"), ConsoleChannel::None);
add(TR("console_help_getmininginfo"), ConsoleChannel::None);
add(TR("console_help_stop"), ConsoleChannel::None);
add("", ConsoleChannel::None);
add(TR("console_click_commands"), ConsoleChannel::Info);
add(TR("console_tab_completion"), ConsoleChannel::Info);
}
ConsoleStatusLine FullNodeConsoleExecutor::toolbarStatus() const
@@ -207,16 +207,16 @@ ConsoleStatusLine FullNodeConsoleExecutor::toolbarStatus() const
// ============================================================================
namespace {
// Colour error/success lines from the lite diagnostics stream for at-a-glance scanning.
ImU32 liteLogColor(const std::string& line)
// Classify a lite diagnostics line into a channel for at-a-glance scanning.
ConsoleChannel liteLogChannel(const std::string& line)
{
const auto has = [&line](const char* s) { return line.find(s) != std::string::npos; };
if (has("failed") || has(" unreachable") || has("blocked") || has("could not") ||
has("Error") || has("error"))
return Error();
return ConsoleChannel::Error;
if (has(": connected") || has("opened") || has("wallet ready") || has("Ready"))
return Success();
return OnSurfaceMedium();
return ConsoleChannel::Success;
return ConsoleChannel::App; // lite diagnostics / wallet log
}
} // namespace
@@ -263,16 +263,16 @@ void LiteConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
startIdx = (added >= snap.size()) ? 0 : snap.size() - static_cast<std::size_t>(added);
}
for (std::size_t i = startIdx; i < snap.size(); ++i)
add(snap[i], liteLogColor(snap[i]));
add(snap[i], liteLogChannel(snap[i]));
diag_gen_ = gen;
}
void LiteConsoleExecutor::printHelp(const ConsoleAddLineFn& add)
{
add(TR("console_available_commands"), ConsoleTab::COLOR_INFO);
add(TR("console_help_clear"), ConsoleTab::COLOR_RESULT);
add(TR("console_help_help"), ConsoleTab::COLOR_RESULT);
add(TR("lite_console_help_passthrough"), ConsoleTab::COLOR_INFO);
add(TR("console_available_commands"), ConsoleChannel::Info);
add(TR("console_help_clear"), ConsoleChannel::None);
add(TR("console_help_help"), ConsoleChannel::None);
add(TR("lite_console_help_passthrough"), ConsoleChannel::Info);
}
std::vector<ConsoleStatusLine> LiteConsoleExecutor::statusLines() const