diff --git a/CHANGELOG.md b/CHANGELOG.md index 73594e1..9899c18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Roo Cline Changelog +## [2.2.1] + +- Fix another diff editing indentation bug + ## [2.2.0] - Incorporate MCP changes from Cline 2.2.0 diff --git a/package-lock.json b/package-lock.json index d7df5da..f290754 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "2.2.0", + "version": "2.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "2.2.0", + "version": "2.2.1", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.26.0", diff --git a/package.json b/package.json index 90d6a57..15d5e18 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Cline", "description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.", "publisher": "RooVeterinaryInc", - "version": "2.2.0", + "version": "2.2.1", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", diff --git a/src/core/diff/strategies/__tests__/search-replace.test.ts b/src/core/diff/strategies/__tests__/search-replace.test.ts index 1d86322..1ad32fe 100644 --- a/src/core/diff/strategies/__tests__/search-replace.test.ts +++ b/src/core/diff/strategies/__tests__/search-replace.test.ts @@ -31,31 +31,6 @@ function hello() { `) }) - it('should handle extra whitespace in search/replace blocks', () => { - const originalContent = `function test() { - return true; -} -` - const diffContent = `test.ts -<<<<<<< SEARCH - -function test() { - return true; -} - -======= -function test() { - return false; -} ->>>>>>> REPLACE` - - const result = strategy.applyDiff(originalContent, diffContent) - expect(result).toBe(`function test() { - return false; -} -`) - }) - it('should match content with different surrounding whitespace', () => { const originalContent = ` function example() { @@ -286,6 +261,27 @@ Invalid diff format` expect(result).toBe(" modified\n still indented\n end\n") }) + it('should preserve indentation when adding new lines after existing content', () => { + const originalContent = ` onScroll={() => updateHighlights()}` + const diffContent = `test.ts +<<<<<<< SEARCH + onScroll={() => updateHighlights()} +======= + onScroll={() => updateHighlights()} + onDragOver={(e) => { + e.preventDefault() + e.stopPropagation() + }} +>>>>>>> REPLACE` + + const result = strategy.applyDiff(originalContent, diffContent) + expect(result).toBe(` onScroll={() => updateHighlights()} + onDragOver={(e) => { + e.preventDefault() + e.stopPropagation() + }}`) + }) + it('should handle complex refactoring with multiple functions', () => { const originalContent = `export async function extractTextFromFile(filePath: string): Promise { try { @@ -519,3 +515,4 @@ export function addLineNumbers(content: string, startLine: number = 1): string { }) }) }) + diff --git a/src/core/diff/strategies/search-replace.ts b/src/core/diff/strategies/search-replace.ts index d871a06..53be541 100644 --- a/src/core/diff/strategies/search-replace.ts +++ b/src/core/diff/strategies/search-replace.ts @@ -74,8 +74,8 @@ Your search/replace content here const lineEnding = originalContent.includes('\r\n') ? '\r\n' : '\n'; // Split content into lines, handling both \n and \r\n - const searchLines = searchContent.trim().split(/\r?\n/); - const replaceLines = replaceContent.trim().split(/\r?\n/); + const searchLines = searchContent.split(/\r?\n/); + const replaceLines = replaceContent.split(/\r?\n/); const originalLines = originalContent.split(/\r?\n/); // Find the search content in the original @@ -130,39 +130,32 @@ Your search/replace content here const currentIndentMatch = line.match(/^[\t ]*/); const currentIndent = currentIndentMatch ? currentIndentMatch[0] : ''; - // If this line has the same indentation level as the search block, - // use the original indentation. Otherwise, calculate the difference - // and preserve the exact type of whitespace characters - if (currentIndent.length === searchIndent.length) { - return originalIndent + line.trim(); - } else { - // Get the corresponding search line's indentation - const searchLineIndex = Math.min(i, searchLines.length - 1); - const searchLineIndent = searchIndents[searchLineIndex]; + // Get the corresponding search line's indentation + const searchLineIndex = Math.min(i, searchLines.length - 1); + const searchLineIndent = searchIndents[searchLineIndex]; - // Get the corresponding original line's indentation - const originalLineIndex = Math.min(i, originalIndents.length - 1); - const originalLineIndent = originalIndents[originalLineIndex]; + // Get the corresponding original line's indentation + const originalLineIndex = Math.min(i, originalIndents.length - 1); + const originalLineIndent = originalIndents[originalLineIndex]; - // If this line has the same indentation as its corresponding search line, - // use the original indentation - if (currentIndent === searchLineIndent) { - return originalLineIndent + line.trim(); - } - - // Otherwise, preserve the original indentation structure - const indentChar = originalLineIndent.charAt(0) || '\t'; - const indentLevel = Math.floor(originalLineIndent.length / indentChar.length); - - // Calculate the relative indentation from the search line - const searchLevel = Math.floor(searchLineIndent.length / indentChar.length); - const currentLevel = Math.floor(currentIndent.length / indentChar.length); - const relativeLevel = currentLevel - searchLevel; - - // Apply the relative indentation to the original level - const targetLevel = Math.max(0, indentLevel + relativeLevel); - return indentChar.repeat(targetLevel) + line.trim(); + // If this line has the same indentation as its corresponding search line, + // use the original indentation + if (currentIndent === searchLineIndent) { + return originalLineIndent + line.trim(); } + + // Otherwise, preserve the original indentation structure + const indentChar = originalLineIndent.charAt(0) || '\t'; + const indentLevel = Math.floor(originalLineIndent.length / indentChar.length); + + // Calculate the relative indentation from the search line + const searchLevel = Math.floor(searchLineIndent.length / indentChar.length); + const currentLevel = Math.floor(currentIndent.length / indentChar.length); + const relativeLevel = currentLevel - searchLevel; + + // Apply the relative indentation to the original level + const targetLevel = Math.max(0, indentLevel + relativeLevel); + return indentChar.repeat(targetLevel) + line.trim(); }); // Construct the final content