feat(console): collapsible JSON in command output
Add fold/unfold of JSON objects and arrays in console command results, built on the refactored channel + model foundation. - ComputeConsoleFoldSpans() (console_input_model): pure brace/bracket matcher over a block of pretty-printed JSON lines; each opener line gets the offset to its matching closer at the same indentation (empty/one-line blocks are not foldable). Unit tested (nested objects, arrays, empty blocks, non-JSON, and a string value that merely contains a brace). - ConsoleModelLine gains foldSpan (relative, so it survives front-eviction by the line cap) + a collapsed flag; ingest() carries the span and toggleCollapsed() flips openers (main thread). addFormattedResult computes the block's spans and ingests them atomically. - computeVisibleLines() skips a collapsed block's interior (opener stays, its foldSpan lines through the closer are hidden); folding is bypassed while a filter is active so every match stays reachable. - drawVisibleLines() draws a fold triangle in the free left gutter of opener lines (result/JSON channels carry no accent bar there), toggled by a click in the gutter cell, and appends a dim " ... }" / " ... ]" summary on collapsed openers. Full-node + lite build clean; ctest green (incl. fold-span + model-fold tests); source hygiene clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,11 @@ namespace ui {
|
||||
struct ConsoleModelLine {
|
||||
std::string text;
|
||||
ConsoleChannel channel = ConsoleChannel::None;
|
||||
// JSON folding: for a line that opens a collapsible block, `foldSpan` is the offset to
|
||||
// its matching closing-bracket line (>= 2); 0 for non-openers. `collapsed` is the user's
|
||||
// fold toggle (main-thread UI state).
|
||||
int foldSpan = 0;
|
||||
bool collapsed = false;
|
||||
};
|
||||
|
||||
class ConsoleModel {
|
||||
@@ -42,8 +47,9 @@ public:
|
||||
explicit ConsoleModel(std::size_t maxLines = kDefaultMaxLines) : max_lines_(maxLines) {}
|
||||
|
||||
// Append a line from ANY thread. Cheap: locks only the pending queue, does not touch
|
||||
// the visible deque. The line becomes visible after the next drain().
|
||||
void ingest(const std::string& text, ConsoleChannel channel);
|
||||
// the visible deque. The line becomes visible after the next drain(). `foldSpan` marks a
|
||||
// JSON block opener (offset to its matching closer); 0 for ordinary lines.
|
||||
void ingest(const std::string& text, ConsoleChannel channel, int foldSpan = 0);
|
||||
|
||||
struct DrainResult {
|
||||
std::size_t added = 0; // lines appended to the visible deque this drain
|
||||
@@ -59,6 +65,10 @@ public:
|
||||
// new output still appears — matching the console's view-only `clear` semantics.
|
||||
void clear();
|
||||
|
||||
// Main thread only. Toggle a foldable line's collapsed state (no-op if out of range or
|
||||
// not a block opener). Returns the new collapsed state.
|
||||
bool toggleCollapsed(std::size_t i);
|
||||
|
||||
// Visible-model access — main thread only (no lock; the deque is main-thread-owned).
|
||||
const std::deque<ConsoleModelLine>& lines() const { return lines_; }
|
||||
std::size_t size() const { return lines_.size(); }
|
||||
|
||||
Reference in New Issue
Block a user