Skip to content

Commit a170a5e

Browse files
committed
Add support for parsing and merging conflict markers using three dots notation in code blocks
1 parent 590e5bd commit a170a5e

4 files changed

Lines changed: 123 additions & 3 deletions

File tree

packages/vscode/src/commands/apply-chat-response-command/utils/clipboard-parser/clipboard-parser.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,26 @@ describe('clipboard-parser', () => {
399399
})
400400
})
401401

402+
it('merges content when merge conflicts use three dots notation', () => {
403+
const test_case = 'merge-conflicts-three-dots'
404+
const text = load_test_case_file(
405+
'standard',
406+
test_case,
407+
`${test_case}.txt`
408+
)
409+
const result = parse_multiple_files({
410+
response: text,
411+
is_single_root_folder_workspace: true
412+
})
413+
414+
expect(result).toHaveLength(1)
415+
expect(result[0]).toMatchObject({
416+
type: 'file',
417+
file_path: 'src/index.ts',
418+
content: load_test_case_file('standard', test_case, '1-file.txt')
419+
})
420+
})
421+
402422
it('parses file paths that use backslashes as separators', () => {
403423
const test_case = 'backslash-paths'
404424
const text = load_test_case_file(

packages/vscode/src/commands/apply-chat-response-command/utils/clipboard-parser/parsers/multiple-files-parser.ts

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,76 @@ const strip_markdown_code_block = (content: string): string => {
4343
return trimmed
4444
}
4545

46+
const process_conflict_markers = (content: string): string => {
47+
const lines = content.split('\n')
48+
const result_lines: string[] = []
49+
50+
let i = 0
51+
while (i < lines.length) {
52+
const line = lines[i]
53+
const startMatch = line.match(/^<<<<<<<\s*(.*)$/)
54+
55+
if (startMatch) {
56+
const labelStart = startMatch[1]
57+
let j = i + 1
58+
let middleIndex = -1
59+
let endIndex = -1
60+
let labelEnd = ''
61+
62+
while (j < lines.length) {
63+
if (lines[j].match(/^=======\s*$/)) {
64+
middleIndex = j
65+
} else if (lines[j].match(/^>>>>>>>\s*(.*)$/)) {
66+
endIndex = j
67+
labelEnd = lines[j].match(/^>>>>>>>\s*(.*)$/)![1]
68+
break
69+
}
70+
j++
71+
}
72+
73+
if (middleIndex !== -1 && endIndex !== -1) {
74+
const leftContentLines = lines.slice(i + 1, middleIndex)
75+
const rightContentLines = lines.slice(middleIndex + 1, endIndex)
76+
77+
const splitByDots = (blockLines: string[]) => {
78+
const parts: string[][] = []
79+
let currentPart: string[] = []
80+
for (const l of blockLines) {
81+
if (l.trim() === '...') {
82+
parts.push(currentPart)
83+
currentPart = []
84+
} else {
85+
currentPart.push(l)
86+
}
87+
}
88+
parts.push(currentPart)
89+
return parts
90+
}
91+
92+
const leftParts = splitByDots(leftContentLines)
93+
const rightParts = splitByDots(rightContentLines)
94+
95+
if (leftParts.length > 1 && leftParts.length === rightParts.length) {
96+
for (let k = 0; k < leftParts.length; k++) {
97+
result_lines.push(`<<<<<<< ${labelStart}`)
98+
result_lines.push(...leftParts[k])
99+
result_lines.push(`=======`)
100+
result_lines.push(...rightParts[k])
101+
result_lines.push(`>>>>>>> ${labelEnd}`)
102+
}
103+
i = endIndex + 1
104+
continue
105+
}
106+
}
107+
}
108+
109+
result_lines.push(line)
110+
i++
111+
}
112+
113+
return result_lines.join('\n')
114+
}
115+
46116
const create_or_update_file_item = (params: {
47117
file_name: string
48118
content: string
@@ -66,16 +136,18 @@ const create_or_update_file_item = (params: {
66136
return
67137
}
68138

139+
const processed_content = process_conflict_markers(content)
140+
69141
const file_key = `${workspace_name || ''}:${file_name}`
70142

71143
if (file_ref_map.has(file_key)) {
72144
const existing_file = file_ref_map.get(file_key)!
73145
const had_content_before = has_real_code(existing_file.content)
74146

75147
if (mode === 'append') {
76-
existing_file.content = existing_file.content + '\n' + content
148+
existing_file.content = existing_file.content + '\n' + processed_content
77149
} else {
78-
existing_file.content = content
150+
existing_file.content = processed_content
79151
}
80152

81153
if (renamed_from) {
@@ -95,7 +167,7 @@ const create_or_update_file_item = (params: {
95167
const new_file: FileItem = {
96168
type: 'file' as const,
97169
file_path: file_name,
98-
content: content,
170+
content: processed_content,
99171
workspace_name: workspace_name,
100172
renamed_from
101173
}
@@ -125,6 +197,11 @@ export const parse_multiple_files = (params: {
125197
}): (FileItem | TextItem)[] => {
126198
const file_content_result = parse_file_content_only(params)
127199
if (file_content_result) {
200+
if (file_content_result.type === 'file') {
201+
file_content_result.content = process_conflict_markers(
202+
file_content_result.content
203+
)
204+
}
128205
return [file_content_result]
129206
}
130207

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<<<<<<< ORIGINAL
2+
console.log("a")
3+
=======
4+
console.log("b")
5+
>>>>>>> UPDATED
6+
<<<<<<< ORIGINAL
7+
console.log("c")
8+
=======
9+
console.log("d")
10+
>>>>>>> UPDATED
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Updated file: `src\index.ts`
2+
3+
```typescript
4+
<<<<<<< ORIGINAL
5+
console.log("a")
6+
...
7+
console.log("c")
8+
=======
9+
console.log("b")
10+
...
11+
console.log("d")
12+
>>>>>>> UPDATED
13+
```

0 commit comments

Comments
 (0)