Add green borders around bash execution component

This commit is contained in:
Mario Zechner 2025-12-08 22:45:05 +01:00
parent bd0d0676d4
commit d5200b4f1c

View file

@ -6,6 +6,7 @@ import { Container, Loader, Spacer, Text, type TUI } from "@mariozechner/pi-tui"
import stripAnsi from "strip-ansi"; import stripAnsi from "strip-ansi";
import { theme } from "../theme/theme.js"; import { theme } from "../theme/theme.js";
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from "../tools/truncate.js"; import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from "../tools/truncate.js";
import { DynamicBorder } from "./dynamic-border.js";
// Preview line limit when not expanded (matches tool execution behavior) // Preview line limit when not expanded (matches tool execution behavior)
const PREVIEW_LINES = 20; const PREVIEW_LINES = 20;
@ -18,24 +19,28 @@ export class BashExecutionComponent extends Container {
private loader: Loader; private loader: Loader;
private truncationResult?: TruncationResult; private truncationResult?: TruncationResult;
private fullOutputPath?: string; private fullOutputPath?: string;
private contentText: Text;
private statusText: Text | null = null;
private expanded = false; private expanded = false;
private contentContainer: Container;
constructor(command: string, ui: TUI) { constructor(command: string, ui: TUI) {
super(); super();
this.command = command; this.command = command;
const borderColor = (str: string) => theme.fg("bashMode", str);
// Add spacer // Add spacer
this.addChild(new Spacer(1)); this.addChild(new Spacer(1));
// Top border
this.addChild(new DynamicBorder(borderColor));
// Content container (holds dynamic content between borders)
this.contentContainer = new Container();
this.addChild(this.contentContainer);
// Command header // Command header
const header = new Text(theme.fg("bashMode", theme.bold(`$ ${command}`)), 1, 0); const header = new Text(theme.fg("bashMode", theme.bold(`$ ${command}`)), 1, 0);
this.addChild(header); this.contentContainer.addChild(header);
// Output area (will be updated)
this.contentText = new Text("", 1, 0);
this.addChild(this.contentText);
// Loader // Loader
this.loader = new Loader( this.loader = new Loader(
@ -44,7 +49,10 @@ export class BashExecutionComponent extends Container {
(text) => theme.fg("muted", text), (text) => theme.fg("muted", text),
"Running... (esc to cancel)", "Running... (esc to cancel)",
); );
this.addChild(this.loader); this.contentContainer.addChild(this.loader);
// Bottom border
this.addChild(new DynamicBorder(borderColor));
} }
/** /**
@ -83,9 +91,8 @@ export class BashExecutionComponent extends Container {
this.truncationResult = truncationResult; this.truncationResult = truncationResult;
this.fullOutputPath = fullOutputPath; this.fullOutputPath = fullOutputPath;
// Stop and remove loader // Stop loader
this.loader.stop(); this.loader.stop();
this.removeChild(this.loader);
this.updateDisplay(); this.updateDisplay();
} }
@ -106,19 +113,23 @@ export class BashExecutionComponent extends Container {
const displayLines = availableLines.slice(-maxDisplayLines); // Show last N lines (tail) const displayLines = availableLines.slice(-maxDisplayLines); // Show last N lines (tail)
const hiddenLineCount = availableLines.length - displayLines.length; const hiddenLineCount = availableLines.length - displayLines.length;
let displayText = ""; // Rebuild content container
this.contentContainer.clear();
// Command header
const header = new Text(theme.fg("bashMode", theme.bold(`$ ${this.command}`)), 1, 0);
this.contentContainer.addChild(header);
// Output
if (displayLines.length > 0) { if (displayLines.length > 0) {
displayText = displayLines.map((line) => theme.fg("muted", line)).join("\n"); const displayText = displayLines.map((line) => theme.fg("muted", line)).join("\n");
this.contentContainer.addChild(new Text("\n" + displayText, 1, 0));
} }
this.contentText.setText(displayText ? "\n" + displayText : ""); // Loader or status
if (this.status === "running") {
// Update/add status text if complete this.contentContainer.addChild(this.loader);
if (this.status !== "running") { } else {
if (this.statusText) {
this.removeChild(this.statusText);
}
const statusParts: string[] = []; const statusParts: string[] = [];
// Show how many lines are hidden (collapsed preview) // Show how many lines are hidden (collapsed preview)
@ -139,8 +150,7 @@ export class BashExecutionComponent extends Container {
} }
if (statusParts.length > 0) { if (statusParts.length > 0) {
this.statusText = new Text("\n" + statusParts.join("\n"), 1, 0); this.contentContainer.addChild(new Text("\n" + statusParts.join("\n"), 1, 0));
this.addChild(this.statusText);
} }
} }
} }