Files
oh-my-pi/packages/coding-agent/src/modes/components/visual-truncate.ts
T
can1357 8ef11355e7 perf(tui,natives): added native text utilities with JS fast path for short strings
- Added native text utilities in pi-natives (visible width, truncation, slicing, segment extraction)
- Wired pi-tui to use native implementations with short-string JS fast path
- Optimized key matching via cached parsed key ids
- Refactored visual truncation to reuse Text instances
- Reduced theme color lookups by switching from Map to plain records
- Regenerated WASM artifacts

Benchmarks (after vs before, lower is better):
- truncateToWidth/ansi: 20.37ms vs 38.13ms (2000 iters)
- sliceWithWidth/ansi: 5.12ms vs 20.39ms
- extractSegments/ansi: 8.92ms vs 27.60ms
- truncateToVisualLines: 3.51ms vs 411.55ms (500 iters)
- visibleWidth/ansi: 0.24ms vs 0.31ms
2026-01-29 10:47:55 +01:00

64 lines
2.0 KiB
TypeScript

/**
* Shared utility for truncating text to visual lines (accounting for line wrapping).
* Used by both tool-execution.ts and bash-execution.ts for consistent behavior.
*/
import { Text } from "@oh-my-pi/pi-tui";
export interface VisualTruncateResult {
/** The visual lines to display */
visualLines: string[];
/** Number of visual lines that were skipped (hidden) */
skippedCount: number;
}
const textCache = new Map<number, Text>();
function getCachedText(paddingX: number): Text {
let text = textCache.get(paddingX);
if (!text) {
text = new Text("", paddingX, 0);
textCache.set(paddingX, text);
}
return text;
}
/**
* Truncate text to a maximum number of visual lines (from the end).
* This accounts for line wrapping based on terminal width.
*
* @param text - The text content (may contain newlines)
* @param maxVisualLines - Maximum number of visual lines to show
* @param width - Terminal/render width
* @param paddingX - Horizontal padding for Text component (default 0).
* Use 0 when result will be placed in a Box (Box adds its own padding).
* Use 1 when result will be placed in a plain Container.
* @returns The truncated visual lines and count of skipped lines
*/
export function truncateToVisualLines(
text: string,
maxVisualLines: number,
width: number,
paddingX: number = 0,
): VisualTruncateResult {
if (!text) {
return { visualLines: [], skippedCount: 0 };
}
// Create a temporary Text component to render and get visual lines
const tempText = getCachedText(paddingX);
if (tempText.getText() !== text) {
tempText.setText(text);
}
const allVisualLines = tempText.render(width);
if (allVisualLines.length <= maxVisualLines) {
return { visualLines: allVisualLines, skippedCount: 0 };
}
// Take the last N visual lines
const truncatedLines = allVisualLines.slice(-maxVisualLines);
const skippedCount = allVisualLines.length - maxVisualLines;
return { visualLines: truncatedLines, skippedCount };
}