Procházet zdrojové kódy

Merge pull request #90 from RooVetGit/fix_diff_bug

Fix indentation bug with diff replacing a single search line
Matt Rubens před 1 rokem
rodič
revize
34fac1c70c

+ 4 - 0
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

+ 2 - 2
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",

+ 1 - 1
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",

+ 22 - 25
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<string> {
 	try {
@@ -519,3 +515,4 @@ export function addLineNumbers(content: string, startLine: number = 1): string {
         })
     })
 })
+

+ 23 - 30
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();
-                }
+            // 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);
+            // 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;
+            // 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();
-            }
+            // 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