diff --git a/packages/coding-agent/src/tui/tool-execution.ts b/packages/coding-agent/src/tui/tool-execution.ts index 21fdf51b..1ddf349b 100644 --- a/packages/coding-agent/src/tui/tool-execution.ts +++ b/packages/coding-agent/src/tui/tool-execution.ts @@ -13,6 +13,13 @@ function shortenPath(path: string): string { return path; } +/** + * Replace tabs with spaces for consistent rendering + */ +function replaceTabs(text: string): string { + return text.replace(/\t/g, " "); +} + /** * Generate a unified diff between old and new strings with line numbers */ @@ -120,7 +127,7 @@ export class ToolExecutionComponent extends Container { const displayLines = lines.slice(0, maxLines); const remaining = lines.length - maxLines; - text += "\n\n" + displayLines.map((line: string) => chalk.dim(line)).join("\n"); + text += "\n\n" + displayLines.map((line: string) => chalk.dim(replaceTabs(line))).join("\n"); if (remaining > 0) { text += chalk.dim(`\n... (${remaining} more lines)`); } @@ -142,7 +149,7 @@ export class ToolExecutionComponent extends Container { const displayLines = lines.slice(0, maxLines); const remaining = lines.length - maxLines; - text += "\n\n" + displayLines.map((line: string) => chalk.dim(line)).join("\n"); + text += "\n\n" + displayLines.map((line: string) => chalk.dim(replaceTabs(line))).join("\n"); if (remaining > 0) { text += chalk.dim(`\n... (${remaining} more lines)`); } diff --git a/packages/coding-agent/test.json b/packages/coding-agent/test.json new file mode 100644 index 00000000..f8001741 --- /dev/null +++ b/packages/coding-agent/test.json @@ -0,0 +1,28 @@ +{ + "name": "test-file", + "version": "1.0.0", + "description": "A test JSON file with tab indentation", + "author": "coding-agent", + "data": { + "items": [ + { + "id": 1, + "name": "First item", + "active": true + }, + { + "id": 2, + "name": "Second item", + "active": false + } + ], + "metadata": { + "created": "2024-11-11", + "tags": [ + "test", + "example", + "json" + ] + } + } +} diff --git a/packages/tui/src/components/markdown.ts b/packages/tui/src/components/markdown.ts index 50045a34..803ce409 100644 --- a/packages/tui/src/components/markdown.ts +++ b/packages/tui/src/components/markdown.ts @@ -103,8 +103,11 @@ export class Markdown implements Component { return result; } + // Replace tabs with 3 spaces for consistent rendering + const normalizedText = this.text.replace(/\t/g, " "); + // Parse markdown to HTML-like tokens - const tokens = marked.lexer(this.text); + const tokens = marked.lexer(normalizedText); // Convert tokens to styled terminal output const renderedLines: string[] = []; diff --git a/packages/tui/src/components/text.ts b/packages/tui/src/components/text.ts index b1b6946a..6e6598da 100644 --- a/packages/tui/src/components/text.ts +++ b/packages/tui/src/components/text.ts @@ -63,8 +63,11 @@ export class Text implements Component { return result; } + // Replace tabs with 3 spaces for consistent rendering + const normalizedText = this.text.replace(/\t/g, " "); + const lines: string[] = []; - const textLines = this.text.split("\n"); + const textLines = normalizedText.split("\n"); for (const line of textLines) { // Measure visible length (strip ANSI codes) diff --git a/packages/tui/src/utils.ts b/packages/tui/src/utils.ts index 64b8d778..59ba5ac9 100644 --- a/packages/tui/src/utils.ts +++ b/packages/tui/src/utils.ts @@ -6,7 +6,10 @@ import stringWidth from "string-width"; * - ANSI escape codes (ignored) * - Emojis and wide characters (counted as 2 columns) * - Combining characters (counted correctly) + * - Tabs (replaced with 3 spaces for consistent width) */ export function visibleWidth(str: string): number { - return stringWidth(str); + // Replace tabs with 3 spaces before measuring + const normalized = str.replace(/\t/g, " "); + return stringWidth(normalized); }