fix: show read tool content preview by default
Previously ReadToolGroupComponent completely ignored the expanded state and discarded result content, making read tool output invisible in the TUI (only showed a one-line path summary with no file content). Changes: - Store expanded state in #expanded field (was discarded with _ prefix) - Store result content text in ReadEntry.contentText (was thrown away) - Show a small code preview (3 lines) by default in collapsed mode - Show full file content when expanded via Ctrl+O - Uses renderCodeCell with PREVIEW_LIMITS.OUTPUT_COLLAPSED for consistent truncation with "... N more lines (Ctrl+O for more)" hint This brings read tool output in line with bash and grep tools which already show previews when collapsed.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import { Container, Text } from "@oh-my-pi/pi-tui";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
import { shortenPath } from "../../tools/render-utils";
|
||||
import { getLanguageFromPath, theme } from "../../modes/theme/theme";
|
||||
import { PREVIEW_LIMITS, shortenPath } from "../../tools/render-utils";
|
||||
import { renderCodeCell } from "../../tui";
|
||||
import type { ToolExecutionHandle } from "./tool-execution";
|
||||
|
||||
type ReadRenderArgs = {
|
||||
@@ -35,11 +36,16 @@ type ReadEntry = {
|
||||
sel?: string;
|
||||
status: "pending" | "success" | "warning" | "error";
|
||||
correctedFrom?: string;
|
||||
contentText?: string;
|
||||
};
|
||||
|
||||
/** Number of code lines to show in collapsed preview mode */
|
||||
const COLLAPSED_PREVIEW_LINES = PREVIEW_LIMITS.OUTPUT_COLLAPSED;
|
||||
|
||||
export class ReadToolGroupComponent extends Container implements ToolExecutionHandle {
|
||||
#entries = new Map<string, ReadEntry>();
|
||||
#text: Text;
|
||||
#expanded = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -81,6 +87,11 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
||||
entry.correctedFrom = undefined;
|
||||
}
|
||||
entry.status = result.isError ? "error" : suffixResolution ? "warning" : "success";
|
||||
// Store the text content for preview/expanded display
|
||||
const textContent = result.content?.find(c => c.type === "text")?.text;
|
||||
if (textContent !== undefined) {
|
||||
entry.contentText = textContent;
|
||||
}
|
||||
this.#updateDisplay();
|
||||
}
|
||||
|
||||
@@ -88,7 +99,8 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
||||
this.#updateDisplay();
|
||||
}
|
||||
|
||||
setExpanded(_expanded: boolean): void {
|
||||
setExpanded(expanded: boolean): void {
|
||||
this.#expanded = expanded;
|
||||
this.#updateDisplay();
|
||||
}
|
||||
|
||||
@@ -99,8 +111,13 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
||||
#updateDisplay(): void {
|
||||
const entries = [...this.#entries.values()];
|
||||
|
||||
// Clear previous children and re-add the text node
|
||||
this.clear();
|
||||
this.#text = new Text("", 0, 0);
|
||||
|
||||
if (entries.length === 0) {
|
||||
this.#text.setText(` ${theme.format.bullet} ${theme.fg("toolTitle", theme.bold("Read"))}`);
|
||||
this.addChild(this.#text);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,6 +126,12 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
||||
const statusSymbol = this.#formatStatus(entry.status);
|
||||
const pathDisplay = this.#formatPath(entry);
|
||||
this.#text.setText(` ${statusSymbol} ${theme.fg("toolTitle", theme.bold("Read"))} ${pathDisplay}`.trimEnd());
|
||||
this.addChild(this.#text);
|
||||
|
||||
// Show content preview (collapsed) or full content (expanded)
|
||||
if (entry.contentText !== undefined) {
|
||||
this.#addContentPreview(entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,6 +146,52 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
||||
}
|
||||
|
||||
this.#text.setText(lines.join("\n"));
|
||||
this.addChild(this.#text);
|
||||
|
||||
// Show content for each entry: full when expanded, preview when collapsed
|
||||
for (const entry of entries) {
|
||||
if (entry.contentText !== undefined) {
|
||||
this.#addContentPreview(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a code-cell content preview below the entry summary.
|
||||
* When collapsed: shows first COLLAPSED_PREVIEW_LINES lines with "… N more lines (Ctrl+O for more)" hint.
|
||||
* When expanded: shows full content.
|
||||
*/
|
||||
#addContentPreview(entry: ReadEntry): void {
|
||||
const lang = getLanguageFromPath(entry.path);
|
||||
const filePath = shortenPath(entry.path);
|
||||
const title = filePath ? `Read ${filePath}` : "Read";
|
||||
let cachedWidth: number | undefined;
|
||||
let cachedLines: string[] | undefined;
|
||||
const expanded = this.#expanded;
|
||||
const component: Component = {
|
||||
render: (width: number) => {
|
||||
if (cachedLines && cachedWidth === width) return cachedLines;
|
||||
cachedLines = renderCodeCell(
|
||||
{
|
||||
code: entry.contentText ?? "",
|
||||
language: lang,
|
||||
title,
|
||||
status: entry.status === "error" ? "error" : entry.status === "pending" ? "pending" : "complete",
|
||||
expanded,
|
||||
codeMaxLines: expanded ? undefined : COLLAPSED_PREVIEW_LINES,
|
||||
width,
|
||||
},
|
||||
theme,
|
||||
);
|
||||
cachedWidth = width;
|
||||
return cachedLines;
|
||||
},
|
||||
invalidate: () => {
|
||||
cachedWidth = undefined;
|
||||
cachedLines = undefined;
|
||||
},
|
||||
};
|
||||
this.addChild(component);
|
||||
}
|
||||
|
||||
#formatPath(entry: ReadEntry): string {
|
||||
|
||||
Reference in New Issue
Block a user