Skip to content

Commit 34fac1c

Browse files
authored
Merge pull request #90 from RooVetGit/fix_diff_bug
Fix indentation bug with diff replacing a single search line
2 parents 08a3d65 + 77d7fc0 commit 34fac1c

File tree

5 files changed

+52
-58
lines changed

5 files changed

+52
-58
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Roo Cline Changelog
22

3+
## [2.2.1]
4+
5+
- Fix another diff editing indentation bug
6+
37
## [2.2.0]
48

59
- Incorporate MCP changes from Cline 2.2.0

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Roo Cline",
44
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "2.2.0",
6+
"version": "2.2.1",
77
"icon": "assets/icons/rocket.png",
88
"galleryBanner": {
99
"color": "#617A91",

src/core/diff/strategies/__tests__/search-replace.test.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,31 +31,6 @@ function hello() {
3131
`)
3232
})
3333

34-
it('should handle extra whitespace in search/replace blocks', () => {
35-
const originalContent = `function test() {
36-
return true;
37-
}
38-
`
39-
const diffContent = `test.ts
40-
<<<<<<< SEARCH
41-
42-
function test() {
43-
return true;
44-
}
45-
46-
=======
47-
function test() {
48-
return false;
49-
}
50-
>>>>>>> REPLACE`
51-
52-
const result = strategy.applyDiff(originalContent, diffContent)
53-
expect(result).toBe(`function test() {
54-
return false;
55-
}
56-
`)
57-
})
58-
5934
it('should match content with different surrounding whitespace', () => {
6035
const originalContent = `
6136
function example() {
@@ -286,6 +261,27 @@ Invalid diff format`
286261
expect(result).toBe(" modified\n still indented\n end\n")
287262
})
288263

264+
it('should preserve indentation when adding new lines after existing content', () => {
265+
const originalContent = ` onScroll={() => updateHighlights()}`
266+
const diffContent = `test.ts
267+
<<<<<<< SEARCH
268+
onScroll={() => updateHighlights()}
269+
=======
270+
onScroll={() => updateHighlights()}
271+
onDragOver={(e) => {
272+
e.preventDefault()
273+
e.stopPropagation()
274+
}}
275+
>>>>>>> REPLACE`
276+
277+
const result = strategy.applyDiff(originalContent, diffContent)
278+
expect(result).toBe(` onScroll={() => updateHighlights()}
279+
onDragOver={(e) => {
280+
e.preventDefault()
281+
e.stopPropagation()
282+
}}`)
283+
})
284+
289285
it('should handle complex refactoring with multiple functions', () => {
290286
const originalContent = `export async function extractTextFromFile(filePath: string): Promise<string> {
291287
try {
@@ -519,3 +515,4 @@ export function addLineNumbers(content: string, startLine: number = 1): string {
519515
})
520516
})
521517
})
518+

src/core/diff/strategies/search-replace.ts

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ Your search/replace content here
7474
const lineEnding = originalContent.includes('\r\n') ? '\r\n' : '\n';
7575

7676
// Split content into lines, handling both \n and \r\n
77-
const searchLines = searchContent.trim().split(/\r?\n/);
78-
const replaceLines = replaceContent.trim().split(/\r?\n/);
77+
const searchLines = searchContent.split(/\r?\n/);
78+
const replaceLines = replaceContent.split(/\r?\n/);
7979
const originalLines = originalContent.split(/\r?\n/);
8080

8181
// Find the search content in the original
@@ -130,39 +130,32 @@ Your search/replace content here
130130
const currentIndentMatch = line.match(/^[\t ]*/);
131131
const currentIndent = currentIndentMatch ? currentIndentMatch[0] : '';
132132

133-
// If this line has the same indentation level as the search block,
134-
// use the original indentation. Otherwise, calculate the difference
135-
// and preserve the exact type of whitespace characters
136-
if (currentIndent.length === searchIndent.length) {
137-
return originalIndent + line.trim();
138-
} else {
139-
// Get the corresponding search line's indentation
140-
const searchLineIndex = Math.min(i, searchLines.length - 1);
141-
const searchLineIndent = searchIndents[searchLineIndex];
133+
// Get the corresponding search line's indentation
134+
const searchLineIndex = Math.min(i, searchLines.length - 1);
135+
const searchLineIndent = searchIndents[searchLineIndex];
142136

143-
// Get the corresponding original line's indentation
144-
const originalLineIndex = Math.min(i, originalIndents.length - 1);
145-
const originalLineIndent = originalIndents[originalLineIndex];
137+
// Get the corresponding original line's indentation
138+
const originalLineIndex = Math.min(i, originalIndents.length - 1);
139+
const originalLineIndent = originalIndents[originalLineIndex];
146140

147-
// If this line has the same indentation as its corresponding search line,
148-
// use the original indentation
149-
if (currentIndent === searchLineIndent) {
150-
return originalLineIndent + line.trim();
151-
}
141+
// If this line has the same indentation as its corresponding search line,
142+
// use the original indentation
143+
if (currentIndent === searchLineIndent) {
144+
return originalLineIndent + line.trim();
145+
}
152146

153-
// Otherwise, preserve the original indentation structure
154-
const indentChar = originalLineIndent.charAt(0) || '\t';
155-
const indentLevel = Math.floor(originalLineIndent.length / indentChar.length);
147+
// Otherwise, preserve the original indentation structure
148+
const indentChar = originalLineIndent.charAt(0) || '\t';
149+
const indentLevel = Math.floor(originalLineIndent.length / indentChar.length);
156150

157-
// Calculate the relative indentation from the search line
158-
const searchLevel = Math.floor(searchLineIndent.length / indentChar.length);
159-
const currentLevel = Math.floor(currentIndent.length / indentChar.length);
160-
const relativeLevel = currentLevel - searchLevel;
151+
// Calculate the relative indentation from the search line
152+
const searchLevel = Math.floor(searchLineIndent.length / indentChar.length);
153+
const currentLevel = Math.floor(currentIndent.length / indentChar.length);
154+
const relativeLevel = currentLevel - searchLevel;
161155

162-
// Apply the relative indentation to the original level
163-
const targetLevel = Math.max(0, indentLevel + relativeLevel);
164-
return indentChar.repeat(targetLevel) + line.trim();
165-
}
156+
// Apply the relative indentation to the original level
157+
const targetLevel = Math.max(0, indentLevel + relativeLevel);
158+
return indentChar.repeat(targetLevel) + line.trim();
166159
});
167160

168161
// Construct the final content

0 commit comments

Comments
 (0)