Open
Conversation
johnny9
reviewed
Mar 30, 2026
Collaborator
johnny9
left a comment
There was a problem hiding this comment.
Noticed issues with scrolling when command responses are large. Switch from a List View to columns fixes it due to the simpler layout mechanism of columns
|
|
||
| // Output area — ListView virtualizes delegates so only visible rows are | ||
| // instantiated, preventing layout churn during long console sessions. | ||
| ListView { |
Collaborator
There was a problem hiding this comment.
The list view has problems with very long command responses. In my testing, the best fix is to convert this to a Flickable+Column+Repeater. With that we just need to make sure the command history buffer has a sensible limit.
MarnixCroes
reviewed
Apr 6, 2026
Contributor
There was a problem hiding this comment.
A few observations from first quick test:
- The entry box should automatically be selected when opening the console window.
- Selecting the entry box does not always work that well. I have to click it twice.
- Up and down keystroke should navigate suggested commands (when there are, for example type only
get), instead of the history - When selecting a suggested option using mouse arrow and clicking it, the entry box gets deselected. Which it shouldn't, so the user can select the command and then press enter. Without having to select the entry box again first and then press enter.
| ContinueButton { | ||
| id: submitButton | ||
| objectName: "consoleSubmitButton" | ||
| text: qsTr("Run") |
Contributor
387cc36 to
676db66
Compare
Port the RPC command line parser from src/qt/rpcconsole.cpp into a standalone class suitable for use in the QML GUI. Handles standard and functional syntax, nested commands, result subscripts, quoted strings, and redacts sensitive arguments (e.g. walletpassphrase). Adds a unit test executable (rpc_console_tests) covering parse-only mode, execution, nested commands, subscripts, and redaction.
Introduce RpcConsoleModel, a QObject that sits between QML and RpcCommandExecutor. It manages command submission, a capped command history with Up/Down navigation, pending-text preservation, an auto-complete list built from node.listRpcCommands(), and an `executing` property for UI busy-state feedback. Commands are dispatched to a background QThread via RpcConsoleWorker so the UI thread is never blocked during RPC execution. Results are delivered back on the main thread via a queued signal. Adds a unit test executable (rpc_console_model_tests) covering history navigation, deduplication, history size cap, and the clear/reset invokables.
The RpcConsoleModel instantiated in bitcoin.cpp uses bitcoin_cli (via RpcCommandExecutor → interfaces::Node::executeRpc). Add it as a PRIVATE dependency of the bitcoinqml target so the linker can resolve the required symbols.
Add a full-featured RPC console page backed by RpcConsoleModel. The output area renders colour-coded lines (request, reply, error) from a ListModel fed by commandResultReceived signals. The input field supports Up/Down history navigation, Enter to submit, and resets the history cursor whenever the user resumes typing. A Clear button empties the output list on demand. Register the QML file in bitcoin_qml.qrc so it is available as a resource to the engine.
Instantiate RpcConsoleModel in QmlGuiMain, connect it to NodeModel::nodeInitialized so its available-command list is populated once the node is ready, and expose it as the 'rpcConsoleModel' context property. Register RpcConsoleModel as an uncreatable QML type so its enums are accessible from QML. Add a 'Console' setting item to NodeSettings that pushes the CommandConsole page onto the navigation stack, consistent with the existing 'Network Traffic' and 'Peers' entries.
Add qml_test_console.py to exercise the CommandConsole page end-to-end: navigating to the page, submitting commands, verifying output lines appear with correct colour-coding, history Up/Down navigation, and the Clear button. Pass -disablewallet to the GUI node in the test harness so the process starts without wallet initialisation, matching a minimal node-only setup appropriate for console testing. Register the new test in the CI workflow so it runs on every push.
The port of RPCParseCommandLine replaced the assert(filter_begin_pos) invariant in close_out_params() with a defensive if-guard. This is incorrect: filter_begin_pos is guaranteed non-zero whenever nDepthInsideSensitive decrements to zero, because it is set in add_to_current_stack() at the same time the depth counter is set to 1. Silently skipping the emplace_back when the invariant is violated would leave sensitive arguments (walletpassphrase, encryptwallet, etc.) unredacted in the history/display output. Restore the assert to match src/qt/rpcconsole.cpp and catch any future logic regressions.
Switch the output delegate from Text to TextEdit with readOnly and selectByMouse enabled, so users can select and copy command results. Text does not support mouse selection; TextEdit with readOnly provides the same rendering while allowing the user to highlight output text.
The help-console text, parse error message, and generic error message were constructed as raw QString literals, making them untranslatable. Replace the file-scope static HELP_CONSOLE_TEXT with an inline tr() call inside the worker's execute() slot, where QObject::tr() is available. Wrap the two error format strings in tr() in both the worker and RpcConsoleModel::submitCommand(). No behavioral change.
QmlTestHarness had -disablewallet baked into its start() method, applying it to every test that uses the harness. This would break any future functional test that exercises wallet functionality. Add an extra_args parameter to QmlTestHarness and pass -disablewallet only from the console test, which does not need wallet support. Also rename parseUnbalancedParenFails to parseImplicitlyClosedParenSucceeds in test_rpccommandexecutor.cpp. The test verifies that parsing succeeds (the parser's trailing-newline injection implicitly closes the paren), so the previous name was the opposite of what the assertion checks.
Explain why importprivkey, dumpprivkey, dumpwallet, and importwallet are intentionally absent from HISTORY_FILTER: their sensitive data is a file path or key blob rather than a passphrase, so redacting them would obscure useful history context without a meaningful security benefit. Also add a comment clarifying the assert(filter_begin_pos) invariant: filter_begin_pos is always set to a position > 0 (at minimum the opening paren or space following the sensitive command name), so the assert is always satisfied before the range is recorded.
Two small fixes to RpcConsoleWorker::execute(): * Emit commandResultReceived before calling setExecuting(false). The previous order created a single-frame window where the submit button was re-enabled before the reply line appeared in the output, allowing a second submission before the user could see the result. * Match "help-console" case-insensitively and after trimming whitespace. The old literal comparison against "help-console\n" silently ignored "HELP-CONSOLE" or a command with trailing spaces.
Commands like listunspent on a large wallet can produce megabytes of JSON. Feeding that into a Text/TextEdit element stalls the GUI layout engine. Cap output at 50,000 characters and append a notice directing the user to bitcoin-cli for the full result when truncation occurs. Adds a unit test (LargeResultNode + QSignalSpy) that exercises the full worker-thread path and verifies the truncation notice appears.
The previous layout used a Repeater inside a Column, which instantiates every output delegate eagerly. Long console sessions accumulate many rows and cause visible layout churn. Switch to ListView so delegates are virtualized — only those visible on screen are instantiated. Move the welcome/security-warning texts into the ListView header (they scroll with content and disappear naturally as output grows). Auto-scroll on new rows is handled by positionViewAtEnd() deferred via Qt.callLater() so it runs after the layout pass. The old Connections on outputScroll.contentItem.contentHeightChanged is removed; onCountChanged is the appropriate hook for ListView.
Expose `executing` as a public page property bound to rpcConsoleModel.executing. Functional tests previously waited on consoleSubmitButton.enabled, which breaks if the button is disabled for any other reason (e.g. empty input). Waiting on the executing flag gives tests a direct, semantic signal that the worker thread has finished. Also move the internal `_navigatingHistory` flag into a QtObject so it does not appear in the page's public API. The flag is an implementation detail of history navigation and has no business being accessible from outside the component.
Three small UX improvements: * Add a TapHandler on the NavigationBar2 header so tapping the header title dismisses the keyboard / unfocuses the input field. * Add a page-level TapHandler (TakeOverForbidden) that unfocuses the input field when the user taps anywhere outside it. Interactive children retain their exclusive grabs and work normally. * Switch the submit button from NavButton to ContinueButton with explicit left/right padding, and disable it when the input field is empty to prevent accidental empty submissions.
The page-level TapHandler added in the previous polish commit does not fire for clicks inside the ListView: Qt 6.2's Flickable childMouseEventFilter disrupts passive grab notifications on ancestor items. Handlers placed inside the ListView's contentItem (z:-1 MouseArea, TapHandler) also fail — Flickable's internal press-grab machinery prevents them from receiving events. Fix this by placing a MouseArea outside the ListView entirely, as a sibling item at z:1 (above the ListView's default z:0). It intercepts every press in the output area, clears focus from the input field, then sets mouse.accepted = false so the event passes through to the ListView for normal scroll and tap handling.
Introduce a reusable scrollable monospace text display backed by a list model, intended to be shared between the RPC console and the debug log page. Built on Flickable + Column + Repeater so child heights sum exactly and the scrollbar stays stable on long rows; virtualization is deliberately omitted and callers must bound the model size. Supports optional left/right columns around the main content column (e.g. line numbers + relative time for the debug log, or timestamps for the console), configurable content text format so consumers opt into RichText explicitly, theme-aware selection colours, and coalesced auto-scroll so bulk appends schedule a single scroll.
…ting to C++ Replace the per-page ListView and JavaScript output buffer in CommandConsole.qml with a binding to a new RpcOutputListModel owned by RpcConsoleModel, rendered through the shared MonospaceOutputView component. The 5000-row cap that previously lived as a JS constant in the QML page now lives on the model and trims the oldest rows under beginRemoveRows / endRemoveRows, and a Q_INVOKABLE clearOutput replaces the ad-hoc clearRequested signal. Pretty-printing of RPC replies is moved from a regex-based JS helper on the HTML-escaped string to a UniValue tree walk in C++. The previous regex colourised anything matching "key":-shaped text and so false-positively coloured substrings inside string values that happened to end with a colon; the tree walk colours only real object keys. Request, reply, error and key colours remain theme- aware and are pushed to the model from QML so dark/light toggles take effect on newly-appended rows. test_rpcconsolemodel exercises the output-model cap, reset, and the key-vs-value discrimination that the regex could not handle.
676db66 to
b1670f5
Compare
Populate the autocomplete list with "help <command>" entries for every registered RPC command, plus the "help-console" meta-command. This lets users discover inline help directly from the completion popup without having to know the exact syntax.
Add a console icon (PNG + SVG source) for use in the command console input bar, and register it in the Qt resource file.
Replace the bordered TextField and "Run" ContinueButton with a cleaner layout: transparent input bar with a thin separator line, a console icon prefix, zero-padding text field, and a compact icon-only submit button with hover/press states. The result is a more compact, chat-style input area that matches the overall dark-theme aesthetic.
Allow users to arrow through autocomplete suggestions with Up/Down keys when the popup is open, and accept the highlighted entry with Tab. The selected item is visually distinguished with the orange accent colour. Changes: - Track autocompleteIndex; reset it when the suggestion list updates - Up/Down keys navigate the popup when visible, fall through to history browsing otherwise - Tab accepts filteredCommands[autocompleteIndex] instead of always [0] - Align popup x to inputField.x so it tracks the text field position - Suppress popup from reopening during programmatic history navigation
Replace the Repeater.onItemAdded + _scrollQueued coalescing approach with a single Connections on the Flickable's contentHeightChanged signal. This ensures the Column has already laid out the new delegate before scrollToBottom() fires, so contentHeight is accurate and the scroll reaches the true bottom.
Migrate the console submit button from a plain Item with manual MouseArea click/hover handling to an AbstractButton with proper background, contentItem, and declarative states. This follows QML best practices and simplifies the hover/pressed visual feedback logic with no behavior change.
Remove the inputField.activeFocus gate from the autocomplete popup open condition. The popup should appear whenever the typed text matches available commands, regardless of whether the input field has active keyboard focus (e.g. after programmatic text changes). Add functional tests covering autocomplete popup visibility, no-match hiding, click-to-apply suggestions, and help-prefix matching.
Add availableCommandsIncludesHelpVariants test that verifies RpcConsoleModel::availableCommands() includes "help <cmd>" variants and "help-console", is sorted case-insensitively, and contains no duplicates. Uses a CommandListNode mock that returns a known set of commands.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Created page for rpc command console. #508
Created option under settings for console.
Preserved parsing logic currently in use.
Added unit and functional tests.