From d8b0ff99864c8c25050166e4e0de84340ad46257 Mon Sep 17 00:00:00 2001 From: Feldwor Date: Fri, 12 Sep 2025 16:35:55 +0300 Subject: [PATCH] Add diff highlighting for Edit tool results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SimpleDiffHighlighter component for color-coded diff display - Add simpleDiffDetector utility for parsing diff content - Enable diff highlighting in both preview and expanded states - Preserve original Edit tool styling (font, spacing, layout) - Support light/dark theme color schemes - Only highlight content with +/- diff markers - Focus: Edit tools only, no MarkdownRenderer changes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- frontend/src/components/MessageComponents.tsx | 1 + .../src/components/SimpleDiffHighlighter.tsx | 74 +++++++++++++++++++ .../messages/CollapsibleDetails.tsx | 31 +++++--- frontend/src/utils/simpleDiffDetector.ts | 48 ++++++++++++ 4 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 frontend/src/components/SimpleDiffHighlighter.tsx create mode 100644 frontend/src/utils/simpleDiffDetector.ts diff --git a/frontend/src/components/MessageComponents.tsx b/frontend/src/components/MessageComponents.tsx index 71f3954a..d19679df 100644 --- a/frontend/src/components/MessageComponents.tsx +++ b/frontend/src/components/MessageComponents.tsx @@ -233,6 +233,7 @@ export function ToolResultMessageComponent({ maxPreviewLines={maxPreviewLines} showPreview={shouldShowPreview} defaultExpanded={defaultExpanded} + useDiffHighlighter={message.toolName === "Edit"} /> ); } diff --git a/frontend/src/components/SimpleDiffHighlighter.tsx b/frontend/src/components/SimpleDiffHighlighter.tsx new file mode 100644 index 00000000..73d2563e --- /dev/null +++ b/frontend/src/components/SimpleDiffHighlighter.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { hasDiffContent, parseDiffLines, type DiffLine } from '../utils/simpleDiffDetector'; +import { useTheme } from '../hooks/useSettings'; + +interface SimpleDiffHighlighterProps { + content: string; + className?: string; +} + +interface DiffLineProps { + line: DiffLine; + isDark: boolean; +} + +function DiffLineComponent({ line, isDark }: DiffLineProps) { + const getLineStyles = () => { + switch (line.type) { + case 'addition': + return isDark + ? `bg-green-900/30 text-green-300` + : `bg-green-50 text-green-700`; + + case 'removal': + return isDark + ? `bg-red-900/30 text-red-300` + : `bg-red-50 text-red-700`; + + default: // context + return isDark + ? `text-emerald-300` + : `text-emerald-700`; + } + }; + + return ( + + {line.content} + + ); +} + +export function SimpleDiffHighlighter({ content, className = '' }: SimpleDiffHighlighterProps) { + const { theme } = useTheme(); + const isDark = theme === 'dark'; + + // Check if content contains diff lines + const isDiff = hasDiffContent(content); + + // If not a diff, render as plain pre + if (!isDiff) { + return ( +
+        {content}
+      
+ ); + } + + // Parse diff lines and render with highlighting + const diffLines = parseDiffLines(content); + + return ( +
+      {diffLines.map((line, index) => (
+        
+          
+          {index < diffLines.length - 1 && '\n'}
+        
+      ))}
+    
+ ); +} \ No newline at end of file diff --git a/frontend/src/components/messages/CollapsibleDetails.tsx b/frontend/src/components/messages/CollapsibleDetails.tsx index 4215c034..2e58d250 100644 --- a/frontend/src/components/messages/CollapsibleDetails.tsx +++ b/frontend/src/components/messages/CollapsibleDetails.tsx @@ -3,6 +3,7 @@ import { createContentPreview, createMoreLinesIndicator, } from "../../utils/contentUtils"; +import { SimpleDiffHighlighter } from "../SimpleDiffHighlighter"; interface CollapsibleDetailsProps { label: string; @@ -20,6 +21,7 @@ interface CollapsibleDetailsProps { showPreview?: boolean; previewContent?: string; previewSummary?: string; + useDiffHighlighter?: boolean; } export function CollapsibleDetails({ @@ -33,6 +35,7 @@ export function CollapsibleDetails({ showPreview = true, previewContent, previewSummary, + useDiffHighlighter = false, }: CollapsibleDetailsProps) { const [isExpanded, setIsExpanded] = useState(defaultExpanded); const hasDetails = details.trim().length > 0; @@ -104,11 +107,15 @@ export function CollapsibleDetails({ className="mt-2 pl-6 border-l-2 border-dashed opacity-80" style={{ borderColor: "inherit" }} > -
-            {contentPreview.preview}
-          
+ {useDiffHighlighter ? ( + + ) : ( +
+              {contentPreview.preview}
+            
+ )}
@@ -120,11 +127,17 @@ export function CollapsibleDetails({
)} {hasDetails && isExpanded && ( -
-          {details}
-        
+ {useDiffHighlighter ? ( + + ) : ( +
+              {details}
+            
+ )} + )} ); diff --git a/frontend/src/utils/simpleDiffDetector.ts b/frontend/src/utils/simpleDiffDetector.ts new file mode 100644 index 00000000..621e1a49 --- /dev/null +++ b/frontend/src/utils/simpleDiffDetector.ts @@ -0,0 +1,48 @@ +/** + * Simple diff detection utility for Edit tool results + */ + +export interface DiffLine { + type: 'addition' | 'removal' | 'context'; + content: string; + originalContent: string; // Content without +/- markers +} + +/** + * Check if content contains diff-style lines (lines starting with + or -) + */ +export function hasDiffContent(content: string): boolean { + const lines = content.split('\n'); + return lines.some(line => + line.startsWith('+') || line.startsWith('-') + ); +} + +/** + * Parse content into diff lines with type classification + */ +export function parseDiffLines(content: string): DiffLine[] { + const lines = content.split('\n'); + + return lines.map(line => { + if (line.startsWith('+')) { + return { + type: 'addition' as const, + content: line, + originalContent: line.substring(1) // Remove + marker + }; + } else if (line.startsWith('-')) { + return { + type: 'removal' as const, + content: line, + originalContent: line.substring(1) // Remove - marker + }; + } else { + return { + type: 'context' as const, + content: line, + originalContent: line + }; + } + }); +} \ No newline at end of file