import React from "react";
import { FileSearch, FileDiff, CheckCircle, AlertTriangle, CircleDashed } from "lucide-react";
import { ToolViewProps } from "./types";
import { extractFilePath, extractStrReplaceContent, formatTimestamp, getToolTitle } from "./utils";
import { GenericToolView } from "./GenericToolView";
import { cn } from "@/lib/utils";
export function StrReplaceToolView({
name = "str-replace",
assistantContent,
toolContent,
assistantTimestamp,
toolTimestamp,
isSuccess = true,
isStreaming = false
}: ToolViewProps) {
const filePath = extractFilePath(assistantContent);
const { oldStr, newStr } = extractStrReplaceContent(assistantContent);
const toolTitle = getToolTitle(name);
if (!oldStr || !newStr) {
return (
);
}
// Perform a character-level diff to identify changes
const generateDiff = (oldText: string, newText: string) => {
const i = 0;
const j = 0;
// Find common prefix length
let prefixLength = 0;
while (prefixLength < oldText.length && prefixLength < newText.length &&
oldText[prefixLength] === newText[prefixLength]) {
prefixLength++;
}
// Find common suffix length
let oldSuffixStart = oldText.length;
let newSuffixStart = newText.length;
while (oldSuffixStart > prefixLength && newSuffixStart > prefixLength &&
oldText[oldSuffixStart - 1] === newText[newSuffixStart - 1]) {
oldSuffixStart--;
newSuffixStart--;
}
// Generate unified diff parts
const parts = [];
// Add common prefix
if (prefixLength > 0) {
parts.push({ text: oldText.substring(0, prefixLength), type: 'unchanged' });
}
// Add the changed middle parts
if (oldSuffixStart > prefixLength) {
parts.push({ text: oldText.substring(prefixLength, oldSuffixStart), type: 'removed' });
}
if (newSuffixStart > prefixLength) {
parts.push({ text: newText.substring(prefixLength, newSuffixStart), type: 'added' });
}
// Add common suffix
if (oldSuffixStart < oldText.length) {
parts.push({ text: oldText.substring(oldSuffixStart), type: 'unchanged' });
}
return parts;
};
const diffParts = generateDiff(oldStr, newStr);
return (
{filePath || 'Unknown file'}
{isStreaming ? (
Processing string replacement...
{filePath && (
{filePath}
)}
) : (
{diffParts.map((part, i) => (
{part.text}
))}
)}
{/* Footer */}
{!isStreaming && (
{isSuccess ? (
) : (
)}
{isSuccess ? 'Replacement applied successfully' : 'Replacement failed'}
)}
{isStreaming && (
Processing string replacement...
)}
{toolTimestamp && !isStreaming
? formatTimestamp(toolTimestamp)
: assistantTimestamp
? formatTimestamp(assistantTimestamp)
: ''}
);
}