|
|
@@ -33,6 +33,10 @@ function levenshteinDistance(a: string, b: string): number {
|
|
|
}
|
|
|
|
|
|
function getSimilarity(original: string, search: string): number {
|
|
|
+ if (original === '' || search === '') {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
// Normalize strings by removing extra whitespace but preserve case
|
|
|
const normalizeStr = (str: string) => str.replace(/\s+/g, ' ').trim();
|
|
|
|
|
|
@@ -71,8 +75,8 @@ If you're not confident in the exact content to search for, use the read_file to
|
|
|
Parameters:
|
|
|
- path: (required) The path of the file to modify (relative to the current working directory ${cwd})
|
|
|
- diff: (required) The search/replace block defining the changes.
|
|
|
-- start_line: (required) The line number where the search block starts.
|
|
|
-- end_line: (required) The line number where the search block ends.
|
|
|
+- start_line: (required) The line number where the search block starts (inclusive).
|
|
|
+- end_line: (required) The line number where the search block ends (inclusive).
|
|
|
|
|
|
Diff format:
|
|
|
\`\`\`
|
|
|
@@ -94,35 +98,84 @@ Original file:
|
|
|
5 | return total
|
|
|
\`\`\`
|
|
|
|
|
|
-Search/Replace content:
|
|
|
+1. Search/replace a specific chunk of code:
|
|
|
\`\`\`
|
|
|
+<apply_diff>
|
|
|
+<path>File path here</path>
|
|
|
+<diff>
|
|
|
<<<<<<< SEARCH
|
|
|
-def calculate_total(items):
|
|
|
total = 0
|
|
|
for item in items:
|
|
|
total += item
|
|
|
return total
|
|
|
=======
|
|
|
-def calculate_total(items):
|
|
|
"""Calculate total with 10% markup"""
|
|
|
return sum(item * 1.1 for item in items)
|
|
|
>>>>>>> REPLACE
|
|
|
+</diff>
|
|
|
+<start_line>2</start_line>
|
|
|
+<end_line>5</end_line>
|
|
|
+</apply_diff>
|
|
|
+\`\`\`
|
|
|
+
|
|
|
+Result:
|
|
|
+\`\`\`
|
|
|
+1 | def calculate_total(items):
|
|
|
+2 | """Calculate total with 10% markup"""
|
|
|
+3 | return sum(item * 1.1 for item in items)
|
|
|
\`\`\`
|
|
|
|
|
|
-Usage:
|
|
|
+2. Insert code at a specific line (start_line and end_line must be the same, and the content gets inserted before whatever is currently at that line):
|
|
|
+\`\`\`
|
|
|
<apply_diff>
|
|
|
<path>File path here</path>
|
|
|
<diff>
|
|
|
-Your search/replace content here
|
|
|
+<<<<<<< SEARCH
|
|
|
+=======
|
|
|
+ """TODO: Write a test for this"""
|
|
|
+>>>>>>> REPLACE
|
|
|
</diff>
|
|
|
-<start_line>1</start_line>
|
|
|
+<start_line>2</start_line>
|
|
|
+<end_line>2</end_line>
|
|
|
+</apply_diff>
|
|
|
+\`\`\`
|
|
|
+
|
|
|
+Result:
|
|
|
+\`\`\`
|
|
|
+1 | def calculate_total(items):
|
|
|
+2 | """TODO: Write a test for this"""
|
|
|
+3 | """Calculate total with 10% markup"""
|
|
|
+4 | return sum(item * 1.1 for item in items)
|
|
|
+\`\`\`
|
|
|
+
|
|
|
+3. Delete code at a specific line range:
|
|
|
+\`\`\`
|
|
|
+<apply_diff>
|
|
|
+<path>File path here</path>
|
|
|
+<diff>
|
|
|
+<<<<<<< SEARCH
|
|
|
+ total = 0
|
|
|
+ for item in items:
|
|
|
+ total += item
|
|
|
+ return total
|
|
|
+=======
|
|
|
+>>>>>>> REPLACE
|
|
|
+</diff>
|
|
|
+<start_line>2</start_line>
|
|
|
<end_line>5</end_line>
|
|
|
-</apply_diff>`
|
|
|
+</apply_diff>
|
|
|
+\`\`\`
|
|
|
+
|
|
|
+Result:
|
|
|
+\`\`\`
|
|
|
+1 | def calculate_total(items):
|
|
|
+\`\`\`
|
|
|
+`
|
|
|
}
|
|
|
|
|
|
applyDiff(originalContent: string, diffContent: string, startLine?: number, endLine?: number): DiffResult {
|
|
|
// Extract the search and replace blocks
|
|
|
- const match = diffContent.match(/<<<<<<< SEARCH\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> REPLACE/);
|
|
|
+ const match = diffContent.match(/<<<<<<< SEARCH\n([\s\S]*?)\n?=======\n([\s\S]*?)\n?>>>>>>> REPLACE/);
|
|
|
if (!match) {
|
|
|
const debugInfo = this.debugEnabled ? `\n\nDebug Info:\n- Expected Format: <<<<<<< SEARCH\\n[search content]\\n=======\\n[replace content]\\n>>>>>>> REPLACE\n- Tip: Make sure to include both SEARCH and REPLACE sections with correct markers` : '';
|
|
|
|
|
|
@@ -133,7 +186,7 @@ Your search/replace content here
|
|
|
}
|
|
|
|
|
|
let [_, searchContent, replaceContent] = match;
|
|
|
-
|
|
|
+
|
|
|
// Detect line ending from original content
|
|
|
const lineEnding = originalContent.includes('\r\n') ? '\r\n' : '\n';
|
|
|
|
|
|
@@ -145,7 +198,7 @@ Your search/replace content here
|
|
|
|
|
|
if (hasLineNumbers(searchContent) && hasLineNumbers(replaceContent)) {
|
|
|
const stripLineNumbers = (content: string) => {
|
|
|
- return content.replace(/^\d+\s+\|(?!\|)/gm, '')
|
|
|
+ return content.replace(/^\d+\s+\|(?!\|)/gm, '');
|
|
|
};
|
|
|
|
|
|
searchContent = stripLineNumbers(searchContent);
|
|
|
@@ -153,8 +206,8 @@ Your search/replace content here
|
|
|
}
|
|
|
|
|
|
// Split content into lines, handling both \n and \r\n
|
|
|
- const searchLines = searchContent.split(/\r?\n/);
|
|
|
- const replaceLines = replaceContent.split(/\r?\n/);
|
|
|
+ const searchLines = searchContent === '' ? [] : searchContent.split(/\r?\n/);
|
|
|
+ const replaceLines = replaceContent === '' ? [] : replaceContent.split(/\r?\n/);
|
|
|
const originalLines = originalContent.split(/\r?\n/);
|
|
|
|
|
|
// First try exact line range if provided
|
|
|
@@ -167,9 +220,15 @@ Your search/replace content here
|
|
|
const exactStartIndex = startLine - 1;
|
|
|
const exactEndIndex = endLine - 1;
|
|
|
|
|
|
- if (exactStartIndex < 0 || exactEndIndex >= originalLines.length || exactStartIndex > exactEndIndex) {
|
|
|
+ if (exactStartIndex < 0 || exactEndIndex > originalLines.length || exactStartIndex > exactEndIndex) {
|
|
|
const debugInfo = this.debugEnabled ? `\n\nDebug Info:\n- Requested Range: lines ${startLine}-${endLine}\n- File Bounds: lines 1-${originalLines.length}` : '';
|
|
|
|
|
|
+ // Log detailed debug information
|
|
|
+ console.log('Invalid Line Range Debug:', {
|
|
|
+ requestedRange: { start: startLine, end: endLine },
|
|
|
+ fileBounds: { start: 1, end: originalLines.length }
|
|
|
+ });
|
|
|
+
|
|
|
return {
|
|
|
success: false,
|
|
|
error: `Line range ${startLine}-${endLine} is invalid (file has ${originalLines.length} lines)${debugInfo}`,
|
|
|
@@ -263,7 +322,7 @@ Your search/replace content here
|
|
|
// Apply the replacement while preserving exact indentation
|
|
|
const indentedReplaceLines = replaceLines.map((line, i) => {
|
|
|
// Get the matched line's exact indentation
|
|
|
- const matchedIndent = originalIndents[0];
|
|
|
+ const matchedIndent = originalIndents[0] || '';
|
|
|
|
|
|
// Get the current line's indentation relative to the search content
|
|
|
const currentIndentMatch = line.match(/^[\t ]*/);
|