Files
ObsidianDragon/src/ui/windows/console_input_model.h
T
DanSandClaude Opus 4.8 f7ed1ae115 perf(console): tail-cap large RPC results without a full copy
A large RPC result was fully split into lines and copied before being
handed to the console, even though only the last few lines could survive
the model's line cap.

- The formatter now takes a line cap and keeps only the last N lines,
  located by a backward newline scan, so a huge result is never fully
  split or copied. JSON classification still keys off the first
  character of the whole result.
- It works over a string view and moves line text through, and fold
  spans are computed over the formatted lines directly instead of a
  separate vector of copies.
- getline semantics are preserved: a trailing newline adds no empty
  line and an empty result yields no lines.

Tests: getline parity for empty, trailing-newline and blank-line inputs,
the backward tail cap, and JSON classification and fold spans over a
capped result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-13 08:23:30 -05:00

78 lines
3.2 KiB
C++

#pragma once
#include <cstddef>
#include <nlohmann/json.hpp>
#include <string>
#include <string_view>
#include <vector>
namespace dragonx {
namespace ui {
struct ConsoleCompletionResult {
std::vector<std::string> matches;
std::string commonPrefix;
};
struct ConsoleRpcCall {
bool valid = false;
std::string method;
nlohmann::json params = nlohmann::json::array();
std::string error; // set (with valid=false) when an argument fails to parse
};
enum class ConsoleResultLineRole {
Result,
Error,
JsonKey,
JsonString,
JsonNumber,
JsonBrace
};
struct ConsoleResultLine {
std::string text;
ConsoleResultLineRole role = ConsoleResultLineRole::Result;
};
const std::vector<std::string>& ConsoleRpcCommandNames();
void AppendConsoleHistory(std::vector<std::string>& history,
const std::string& command,
std::size_t maxEntries = 100);
int NavigateConsoleHistoryIndex(int currentIndex,
std::size_t historySize,
bool up);
std::string ConsoleHistoryEntry(const std::vector<std::string>& history,
int historyIndex);
ConsoleCompletionResult CompleteConsoleCommand(const std::string& input);
std::vector<std::string> FormatConsoleCompletionLines(const std::vector<std::string>& matches,
std::size_t maxLineLength = 60);
// A tokenized console argument. `quoted` is true when the token came from a "..."/'...' literal,
// so BuildConsoleRpcCall must send it verbatim as a JSON string (never coerce it to a number/bool).
struct ConsoleArg {
std::string text;
bool quoted = false;
};
std::vector<ConsoleArg> ParseConsoleCommandArgsTagged(const std::string& command);
std::vector<std::string> ParseConsoleCommandArgs(const std::string& command);
ConsoleRpcCall BuildConsoleRpcCall(const std::string& command);
// Splits an RPC result into classified lines (std::getline semantics: a trailing '\n' adds no
// empty line, an empty result yields none). `maxLines` > 0 keeps only the LAST maxLines lines,
// found by a backward newline scan so a huge result is never fully split/copied. The JSON
// classification still keys off the first char of the whole result. 0 = no cap.
std::vector<ConsoleResultLine> FormatConsoleRpcResultLines(std::string_view result,
bool isError,
std::size_t maxLines = 0);
// For a block of pretty-printed JSON lines, return a per-line fold span: for a line that
// opens a collapsible block (its last non-space char is '{' or '[') the value is the offset
// to its matching closing-bracket line at the same indentation; 0 for every other line and
// for empty/one-line blocks not worth folding (span < 2). Pure; used to drive console
// JSON folding.
std::vector<int> ComputeConsoleFoldSpans(const std::vector<std::string>& lines);
// Same as ComputeConsoleFoldSpans, over formatted result lines directly (no text copies).
std::vector<int> ComputeConsoleResultFoldSpans(const std::vector<ConsoleResultLine>& lines);
} // namespace ui
} // namespace dragonx