feat(console): left-edge channel accent bar (replaces inline log prefixes)

Each line gets a `channel` inferred in addLine() from its color and any
"[daemon]"/"[xmrig]"/"[app]"/"[rpc]" prefix, which is then stripped. renderOutput draws
a thin colored bar in the existing left margin (padX) per line — node log (blue), mining
(amber), app (teal), rpc (secondary), command (accent), error (red). Drawn in the margin
so it never touches the text layout or selection; filtering is unaffected (it keys off
color, not the prefix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 16:30:43 -05:00
parent e9121fe49e
commit e0d6d6bc4d
2 changed files with 51 additions and 4 deletions

View File

@@ -813,7 +813,30 @@ void ConsoleTab::renderOutput()
const auto& segs = visible_wrap_segments_[vi];
ImVec2 lineOrigin = ImGui::GetCursorScreenPos();
float totalH = wrapped_heights_[vi];
// Left-edge channel accent bar, drawn in the padX margin so it never overlaps
// the text or the selection highlight.
if (line.channel != CH_NONE) {
ImU32 barCol = 0;
switch (line.channel) {
case CH_COMMAND: barCol = Primary(); break;
case CH_ERROR: barCol = Error(); break;
case CH_RPC: barCol = Secondary(); break;
case CH_DAEMON: barCol = IM_COL32(90, 130, 190, 210); break; // node log — blue
case CH_XMRIG: barCol = Warning(); break; // mining — amber
case CH_APP: barCol = IM_COL32(120, 190, 160, 210); break; // app — teal
case CH_INFO: barCol = OnSurfaceDisabled(); break;
default: break;
}
if (barCol != 0) {
float barW = 3.0f * Layout::hScale();
float barX = output_origin_.x - padX + 3.0f * Layout::hScale();
dl->AddRectFilled(ImVec2(barX, lineOrigin.y + 1.0f),
ImVec2(barX + barW, lineOrigin.y + totalH - 1.0f),
barCol, barW * 0.5f);
}
}
// Determine byte-level selection range for this line
int selByteStart = 0, selByteEnd = 0;
bool lineSelected = false;
@@ -1488,8 +1511,27 @@ void ConsoleTab::renderStatusHeader(ConsoleCommandExecutor& exec)
void ConsoleTab::addLine(const std::string& line, ImU32 color)
{
std::lock_guard<std::mutex> lock(lines_mutex_);
lines_.push_back({line, color});
// Infer the channel (for the left accent bar) from the color, then strip the now
// redundant "[daemon]"/"[xmrig]"/"[app]" text prefix so the bar carries the source.
int channel = CH_NONE;
if (color == COLOR_ERROR) channel = CH_ERROR;
else if (color == COLOR_RPC) channel = CH_RPC;
else if (color == COLOR_COMMAND) channel = CH_COMMAND;
else if (color == COLOR_DAEMON) channel = CH_DAEMON;
else if (color == COLOR_INFO) channel = CH_INFO;
std::string text = line;
auto stripPrefix = [&text, &channel](const char* p, int ch) {
const size_t n = std::strlen(p);
if (text.rfind(p, 0) == 0) { text.erase(0, n); channel = ch; }
};
stripPrefix("[daemon] ", CH_DAEMON);
stripPrefix("[xmrig] ", CH_XMRIG);
stripPrefix("[app] ", CH_APP);
stripPrefix("[rpc] ", CH_RPC);
lines_.push_back({text, color, channel});
// Limit buffer size — adjust selection indices when lines are removed
// from the front so the highlight stays on the text the user selected.

View File

@@ -88,11 +88,16 @@ public:
static ImU32 COLOR_RPC;
private:
// Line source, for the left-edge channel accent bar. Inferred in addLine() from the
// color + any "[daemon]"/"[xmrig]"/"[app]" prefix (which is then stripped).
enum Channel { CH_NONE = 0, CH_COMMAND, CH_INFO, CH_ERROR, CH_RPC, CH_DAEMON, CH_XMRIG, CH_APP };
struct ConsoleLine {
std::string text;
ImU32 color;
int channel = CH_NONE;
};
void addCommandResult(const std::string& cmd, const std::string& result, bool is_error = false);
// Format + color a completed command result (JSON-aware) into console lines.
void addFormattedResult(const std::string& result, bool is_error);