Files
ObsidianDragon/src/ui/windows/console_model.cpp
DanS 245d9bf976 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>
2026-07-01 20:11:44 -05:00

57 lines
1.2 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "console_model.h"
#include <utility>
namespace dragonx {
namespace ui {
void ConsoleModel::ingest(const std::string& text, ConsoleChannel channel, int foldSpan)
{
std::lock_guard<std::mutex> lock(ingest_mutex_);
ConsoleModelLine line;
line.text = text;
line.channel = channel;
line.foldSpan = foldSpan;
pending_.push_back(std::move(line));
}
ConsoleModel::DrainResult ConsoleModel::drain()
{
std::vector<ConsoleModelLine> incoming;
{
std::lock_guard<std::mutex> lock(ingest_mutex_);
if (pending_.empty()) return {};
incoming.swap(pending_);
}
DrainResult result;
result.added = incoming.size();
for (auto& line : incoming)
lines_.push_back(std::move(line));
while (lines_.size() > max_lines_) {
lines_.pop_front();
++result.popped;
}
return result;
}
void ConsoleModel::clear()
{
lines_.clear();
}
bool ConsoleModel::toggleCollapsed(std::size_t i)
{
if (i >= lines_.size() || lines_[i].foldSpan <= 0) return false;
lines_[i].collapsed = !lines_[i].collapsed;
return lines_[i].collapsed;
}
} // namespace ui
} // namespace dragonx