Files
ObsidianDragon/src/ui/windows/console_tab.h
T
DanSandClaude Opus 4.8 5c570613c8 feat(console): lite backend command-reference modal
Give the lite console the parity analog of the full-node RPC command
reference: the same searchable two-pane modal (browse/search, detail
pane, examples, Insert / Insert & run, destructive confirm), driven by
the lite backend's own command set instead of daemon RPC.

- ConsoleCommandExecutor::commandReference() returns the category table
  (full node = consoleCommandCategories(); lite = new
  liteConsoleCommandCategories() -- 25 backend verbs in 5 categories).
  The shared renderCommandsPopup reads the table from the executor.
- The Commands button now shows for both variants (gated on
  commandReference()!=nullptr); title/tooltip/arg-quoting branch on
  hasRpcReference() (clarified to mean "speaks JSON-RPC / full node").
- Lite args are bare tokens (the backend takes one unsplit arg string
  and does not strip quotes), so the param-builder's JSON string
  auto-quoting is disabled for lite -- Insert & run emits runnable bare
  commands. send uses the JSON-array form (its positional form is
  unreachable via the single-arg transport); new uses zs/R; import
  takes just the key (the backend hardcodes birthday=0).

Adds 7 i18n keys across all 8 languages (additive). Full-node behavior
is unchanged. Adversarially reviewed (data vs the backend registry,
plumbing/regression, i18n) with all findings fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 12:27:51 -05:00

205 lines
9.2 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
#include "console_channel.h"
#include "console_model.h"
#include "console_scroll_controller.h"
#include "console_selection_controller.h"
#include "console_text_layout.h"
#include "../layout.h"
#include "../../daemon/embedded_daemon.h"
#include "../../daemon/xmrig_manager.h"
#include "../../rpc/rpc_client.h"
#include "../../rpc/rpc_worker.h"
#include <string>
#include <vector>
#include <deque>
#include <mutex>
namespace dragonx {
namespace ui {
class ConsoleCommandExecutor;
struct ConsoleLogFilterCaps;
struct ConsoleCommandEntry;
/**
* @brief Console tab — a rich terminal shared by the full-node and lite variants.
*
* The command execution + log sources are provided by a ConsoleCommandExecutor, so this
* one widget serves both dragonxd (RPC) and the lite backend.
*/
class ConsoleTab {
public:
ConsoleTab();
~ConsoleTab();
/**
* @brief Render the console tab against a backend executor.
*/
void render(ConsoleCommandExecutor& exec);
/**
* @brief Render the command-reference popup at top-level scope.
* Must be called outside any child window so the modal blocks all input. `exec` supplies the
* reference table (full-node RPC vs lite backend verbs); may be null (no console yet) -> no-op.
*/
void renderCommandsPopupModal(ConsoleCommandExecutor* exec);
// Debug/UI-sweep hook: force the RPC command-reference popup open/closed so the full UI sweep
// can capture it (the popup is otherwise opened only by a toolbar button).
void sweepSetCommandsPopup(bool open) { show_commands_popup_ = open; }
/**
* @brief Add a line to the console output
*/
void addLine(const std::string& line, ConsoleChannel channel = ConsoleChannel::None);
void addRpcTraceLine(const std::string& source, const std::string& method);
/**
* @brief Clear console output
*/
void clear();
// Scanline effect toggle (set from settings)
static bool s_scanline_enabled;
// Console output zoom factor (1.0 = default caption font size)
static float s_console_zoom;
// Draw the per-line left color accent bars (channel-colored). Toggled from the toolbar.
static bool s_line_accents_enabled;
// Color output text per channel. When false the console is monochrome text. Toolbar-toggled.
static bool s_line_text_color_enabled;
// Show/hide daemon output messages
static bool s_daemon_messages_enabled;
// Show only error messages (filter toggle)
static bool s_errors_only_enabled;
// Show app RPC calls made through RPCClient (method/source only)
static bool s_rpc_trace_enabled;
// Show "[app] ..." wallet log lines
static bool s_app_messages_enabled;
/// Refresh console text colors for current theme (call after theme switch)
static void refreshColors();
// Colors — follow active theme (public for use by notification forwarding)
static ImU32 COLOR_COMMAND;
static ImU32 COLOR_RESULT;
static ImU32 COLOR_ERROR;
static ImU32 COLOR_DAEMON;
static ImU32 COLOR_INFO;
static ImU32 COLOR_RPC;
private:
// Text color for a channel, resolved from the current theme (COLOR_* + material). Each
// line stores only its semantic ConsoleChannel (in ConsoleModel); the text color and
// the left accent-bar color are both derived from it at draw time.
ImU32 channelTextColor(ConsoleChannel channel) const;
// Saturated accent color for a channel — the left accent-bar color, also used to tint the
// matching toolbar filter toggle. 0 for channels that get no accent (result/JSON/None).
static ImU32 channelAccentColor(ConsoleChannel channel);
// Drain the thread-safe ingest queue into the visible model (once per frame, main
// thread), applying the line cap + selection/scroll bookkeeping for the new lines.
void drainModel();
// Format a completed command result (JSON role -> channel) into console lines.
void addFormattedResult(const std::string& result, bool is_error);
void renderStatusHeader(ConsoleCommandExecutor& exec);
void renderCommandsPopup(ConsoleCommandExecutor& exec);
// right pane; jsonArgs=true (full-node RPC) auto-quotes string args, false (lite) inserts bare
void renderCommandDetail(const ConsoleCommandEntry& cmd, const char* catLabel, bool jsonArgs);
void insertCommandToInput(const ConsoleCommandEntry& cmd); // fill input + close the modal
// renderToolbar() draws the top bar; these are its sub-steps:
void renderToolbar(ConsoleCommandExecutor& exec);
void drawToolbarStatus(ConsoleCommandExecutor& exec); // backend status dot + label
void drawLogFilterToggles(const ConsoleLogFilterCaps& caps); // color-coded filter checkboxes
void drawFilterInput(); // text filter + match count
void drawZoomControls(); // zoom -/+ buttons
// renderInput() draws the command line; dispatch is factored out:
void renderInput(ConsoleCommandExecutor& exec);
// Echo + handle a submitted command line (built-ins + submit). True if non-empty/handled.
bool submitConsoleCommand(ConsoleCommandExecutor& exec, const std::string& cmd);
// renderOutput() orchestrates the scrollable output area; these are its sub-steps:
void renderOutput();
void computeVisibleLines(bool& hasTextFilter, std::string& filterLower); // -> visible_indices_
void handleOutputInteraction(ImVec2 mousePos, bool mouseInOutput); // wheel/selection/keys
void drawVisibleLines(float padX, float lineHeight, bool hasTextFilter,
const std::string& filterLower); // bars/guides/highlight/text
void drawNewOutputIndicator(); // jump-to-bottom pill
void drawOutputContextMenu(); // right-click menu
// Map a screen point to a raw {line, col} position via this frame's wrapped layout.
// (View-side because it needs layout_ + output_origin_; feeds the selection controller.)
ConsoleTextPos screenToTextPos(ImVec2 screen_pos) const;
// The current selection's text (via selection_ over the visible model). "" if inactive.
std::string selectedText() const;
// Thread-safe line store: producers on any thread call model_.ingest(); the main
// thread drains it once per frame in render(). The visible deque is main-thread-only.
ConsoleModel model_;
std::vector<std::string> command_history_;
int history_index_ = -1;
char input_buffer_[4096] = {0};
bool stop_confirm_pending_ = false; // 'stop' typed once, awaiting a confirming second 'stop'
// (log-ingestion cursors + result queue moved to the ConsoleCommandExecutor)
// Auto-scroll state machine (pin-to-bottom, wheel-up cooldown, new-line backlog count).
ConsoleScrollController scroll_;
// Text-selection state + logic (anchor/caret, ordering, extraction, eviction shift).
ConsoleSelectionController selection_;
float output_scroll_y_ = 0.0f; // Track scroll position for selection
ImVec2 output_origin_ = {0, 0}; // Top-left of output area
float output_line_height_ = 0.0f; // Text line height (for scanline alignment)
struct ScanlineRow {
float yTop = 0.0f;
float yBot = 0.0f;
int rowIndex = 0;
};
std::vector<ScanlineRow> scanline_rows_;
// Output filter
char filter_text_[128] = {0};
mutable int filter_match_count_ = 0; // lines matching the text filter (for the toolbar)
std::string context_token_; // hash/address under the cursor at right-click
mutable std::vector<int> visible_indices_; // Cached for selection mapping
bool folding_active_ = true; // fold UI shown only in the unfiltered (foldable) view
bool has_text_filter_ = false; // computed once per frame (before the toolbar draws it)
std::string filter_lower_; // lowercased filter needle for match highlighting
// Wrap layout for the visible lines (segments + per-line heights + cumulative Y),
// recomputed each frame by the pure BuildConsoleLayout (console_text_layout.h) and
// consumed by the renderer + hit-testing.
mutable ConsoleLayout layout_;
// Commands popup (command explorer) — indexes into the active executor's commandReference()
// table (full-node RPC commands or the lite backend verbs), not always the full-node one.
bool show_commands_popup_ = false;
char command_search_[128] = {0}; // reference search filter (cleared when the modal opens)
int cmd_sel_cat_ = -1; // detail-pane selection: category index into that table
int cmd_sel_idx_ = -1; // detail-pane selection: command index within that category
std::string pending_submit_; // command to run next frame (deferred so the modal needs no executor)
const ConsoleCommandEntry* run_confirm_cmd_ = nullptr; // destructive "Insert & run" awaiting confirmation
char cmd_param_bufs_[6][256] = {{0}}; // parameter-builder input fields
const ConsoleCommandEntry* cmd_param_owner_ = nullptr; // command the param buffers currently hold
};
} // namespace ui
} // namespace dragonx