Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/src/components/MessageComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export function ToolResultMessageComponent({
maxPreviewLines={maxPreviewLines}
showPreview={shouldShowPreview}
defaultExpanded={defaultExpanded}
useDiffHighlighter={message.toolName === "Edit"}
/>
);
}
Expand Down
74 changes: 74 additions & 0 deletions frontend/src/components/SimpleDiffHighlighter.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<span className={getLineStyles()}>
{line.content}
</span>
);
}

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 (
<pre className={`whitespace-pre-wrap font-mono leading-relaxed ${className}`}>
{content}
</pre>
);
}

// Parse diff lines and render with highlighting
const diffLines = parseDiffLines(content);

return (
<pre className={`whitespace-pre-wrap font-mono leading-relaxed ${className}`}>
{diffLines.map((line, index) => (
<React.Fragment key={index}>
<DiffLineComponent
line={line}
isDark={isDark}
/>
{index < diffLines.length - 1 && '\n'}
</React.Fragment>
))}
</pre>
);
}
31 changes: 22 additions & 9 deletions frontend/src/components/messages/CollapsibleDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
createContentPreview,
createMoreLinesIndicator,
} from "../../utils/contentUtils";
import { SimpleDiffHighlighter } from "../SimpleDiffHighlighter";

interface CollapsibleDetailsProps {
label: string;
Expand All @@ -20,6 +21,7 @@ interface CollapsibleDetailsProps {
showPreview?: boolean;
previewContent?: string;
previewSummary?: string;
useDiffHighlighter?: boolean;
}

export function CollapsibleDetails({
Expand All @@ -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;
Expand Down Expand Up @@ -104,11 +107,15 @@ export function CollapsibleDetails({
className="mt-2 pl-6 border-l-2 border-dashed opacity-80"
style={{ borderColor: "inherit" }}
>
<pre
className={`whitespace-pre-wrap ${colorScheme.content} text-xs font-mono leading-relaxed`}
>
{contentPreview.preview}
</pre>
{useDiffHighlighter ? (
<SimpleDiffHighlighter content={contentPreview.preview} className="text-xs leading-relaxed" />
) : (
<pre
className={`whitespace-pre-wrap ${colorScheme.content} text-xs font-mono leading-relaxed`}
>
{contentPreview.preview}
</pre>
)}
<div
className={`${colorScheme.content} text-xs opacity-60 mt-1 italic`}
>
Expand All @@ -120,11 +127,17 @@ export function CollapsibleDetails({
</div>
)}
{hasDetails && isExpanded && (
<pre
className={`whitespace-pre-wrap ${colorScheme.content} text-xs font-mono leading-relaxed mt-2 pl-6 border-l-2 ${colorScheme.border}`}
<div
className={`${colorScheme.content} text-xs leading-relaxed mt-2 pl-6 border-l-2 ${colorScheme.border}`}
>
{details}
</pre>
{useDiffHighlighter ? (
<SimpleDiffHighlighter content={details} />
) : (
<pre className="whitespace-pre-wrap font-mono leading-relaxed">
{details}
</pre>
)}
</div>
)}
</div>
);
Expand Down
48 changes: 48 additions & 0 deletions frontend/src/utils/simpleDiffDetector.ts
Original file line number Diff line number Diff line change
@@ -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
};
}
});
}
Loading