Skip to content

Commit 29726c1

Browse files
committed
Add test and fix for parsing diff with file path in markdown heading despite intermediate text containing a path
1 parent 62c0cd1 commit 29726c1

6 files changed

Lines changed: 51 additions & 19 deletions

File tree

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,29 @@ describe('clipboard-parser', () => {
15821582
})
15831583
})
15841584

1585+
it('parses diff format with file path in heading, with intermediate text before the code block', () => {
1586+
const test_case = 'diff-markdown-path-above-with-text-containing-path'
1587+
const text = load_test_case_file(
1588+
test_case,
1589+
'diff-markdown-path-above-with-text-containing-path.txt'
1590+
)
1591+
const result = parse_response({
1592+
response: text,
1593+
is_single_root_folder_workspace: true
1594+
})
1595+
1596+
expect(result).toHaveLength(2)
1597+
expect(result[0]).toMatchObject({
1598+
type: 'text',
1599+
content: load_test_case_file(test_case, '1-text.txt')
1600+
})
1601+
expect(result[1]).toMatchObject({
1602+
type: 'diff',
1603+
file_path: 'src/index.ts',
1604+
content: load_test_case_file(test_case, '2-file.txt')
1605+
})
1606+
})
1607+
15851608
it('parses diff with broken hunk header after git header', () => {
15861609
const test_case = 'diff-git-broken-hunk-header'
15871610
const text = load_test_case_file(test_case, `${test_case}.txt`)

packages/vscode/src/commands/apply-chat-response-command/utils/clipboard-parser/extract-diff-patches/extract-diffs.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ const find_file_path_before_block = (params: {
125125
max_lines_back?: number
126126
}): { file_path?: string; workspace_name?: string } => {
127127
const max_back = params.max_lines_back || 5
128+
let candidate: { file_path?: string; workspace_name?: string } | undefined
128129

129130
for (
130131
let j = params.block_start - 1;
@@ -145,11 +146,19 @@ const find_file_path_before_block = (params: {
145146
raw_file_path: extracted,
146147
is_single_root_folder_workspace: params.is_single_root
147148
})
148-
return { file_path: extracted, workspace_name }
149+
150+
// If we find a heading with a path, it takes precedence over anything below it
151+
if (prev_line.startsWith('###')) {
152+
return { file_path: extracted, workspace_name }
153+
}
154+
155+
if (!candidate) {
156+
candidate = { file_path: extracted, workspace_name }
157+
}
149158
}
150159
}
151160

152-
return {}
161+
return candidate || {}
153162
}
154163

155164
const remove_path_line_from_text_block = (params: {
@@ -266,7 +275,6 @@ const process_collected_patch_lines = (params: {
266275
!is_new_file &&
267276
!is_deleted_file
268277

269-
// For new files, file_path is to_path. For deleted files or renamed files, it's from_path.
270278
const file_path = from_path && from_path != '/dev/null' ? from_path : to_path
271279

272280
if (!file_path || file_path == '/dev/null') {
@@ -341,24 +349,20 @@ const convert_code_block_to_new_file_diff = (params: {
341349
return null
342350
}
343351

344-
// Regex to find file path. It can be commented or not.
345-
// It handles paths with slashes, backslashes, dots, alphanumerics, underscores, and hyphens.
346352
const path_regex = /(?:(?:\/\/|#|--|<!--)\s*)?([\w./\\-]+)/
347353
const xml_path_regex = /<([\w-]+)\s+path=(?:["']([^"']+)["']|([^>\s]+))/
348354

349355
let file_path: string | undefined = params.file_path_hint
350356
let path_line_index = -1
351357
let content_lines: string[] = []
352358

353-
// Check for XML path format
354359
const first_line = params.lines.length > 0 ? params.lines[0].trim() : ''
355360
const xml_match = first_line.match(xml_path_regex)
356361

357362
if (xml_match && xml_match[1] && (xml_match[2] || xml_match[3])) {
358363
const xml_tag_name = xml_match[1]
359364
const potential_path = normalize_path(xml_match[2] || xml_match[3])
360365
if (potential_path.endsWith('/')) {
361-
// This is a directory, not a file.
362366
return null
363367
}
364368
file_path = potential_path
@@ -398,11 +402,9 @@ const convert_code_block_to_new_file_diff = (params: {
398402
content_lines = inner_lines
399403
}
400404
} else {
401-
// malformed, maybe path is on first line, and content follows
402405
content_lines = params.lines.slice(1)
403406
}
404407
} else {
405-
// Look for a file path in the first few lines of the code block
406408
for (let i = 0; i < Math.min(params.lines.length, 5); i++) {
407409
const line = params.lines[i].trim()
408410
const match = line.match(path_regex)
@@ -422,7 +424,7 @@ const convert_code_block_to_new_file_diff = (params: {
422424
if (is_just_path_and_location) {
423425
file_path = normalize_path(potential_path)
424426
path_line_index = i
425-
break // Found it, stop searching.
427+
break
426428
}
427429
}
428430
}
@@ -592,7 +594,6 @@ const extract_all_code_block_patches = (params: {
592594
}
593595
code_blocks.push(...xml_blocks)
594596
code_blocks.sort((a, b) => a.start - b.start)
595-
// First, identify all files that have explicit diff blocks.
596597
const files_with_diffs = new Set<string>()
597598
const diff_block_patches = new Map<number, Diff[]>()
598599

@@ -655,7 +656,6 @@ const extract_all_code_block_patches = (params: {
655656

656657
let last_block_end = -1
657658

658-
// Process each found code block in order of appearance.
659659
for (let i = 0; i < code_blocks.length; i++) {
660660
const block = code_blocks[i]
661661
const block_lines =
@@ -710,7 +710,6 @@ const extract_all_code_block_patches = (params: {
710710
items.push(...patches)
711711
last_block_end = block.end
712712
} else {
713-
// Check if this block was a hint for the next block.
714713
if (i < code_blocks.length - 1) {
715714
const next_block = code_blocks[i + 1]
716715
if (next_block.type === 'diff' || next_block.type === 'patch') {
@@ -719,7 +718,6 @@ const extract_all_code_block_patches = (params: {
719718
if (non_empty_lines.length === 1) {
720719
const match = non_empty_lines[0].match(xml_path_regex)
721720
if (match && match[1]) {
722-
// This was a hint for the next block, so we should skip processing it as a file content block.
723721
if (text_before.trim()) {
724722
items.push({ type: 'text', content: text_before.trim() })
725723
}
@@ -730,7 +728,6 @@ const extract_all_code_block_patches = (params: {
730728
}
731729
}
732730

733-
// Check if there's a comment line before the code block with a file path
734731
const hint_result = find_file_path_before_block({
735732
lines,
736733
block_start: block.start,
@@ -770,8 +767,6 @@ const extract_all_code_block_patches = (params: {
770767
last_block_end = block.end
771768
}
772769
}
773-
// If it's not a diff, patch, or hint, it's just a regular code block.
774-
// We don't do anything here, so it gets included in the next text block.
775770
}
776771
}
777772

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,6 @@ export const parse_multiple_files = (params: {
377377
last_seen_file_path_was_header = is_header_line
378378
}
379379
} else {
380-
// Check if this line is a plain file path followed by a code block
381380
let is_lone_path_on_this_line = false
382381
if (!last_seen_file_path_comment) {
383382
let trimmed = line.trim()
@@ -394,7 +393,6 @@ export const parse_multiple_files = (params: {
394393
trimmed = trimmed.slice(0, -1)
395394
}
396395

397-
// Check if it looks like a file path and if the next non-empty line is a code block
398396
if (
399397
trimmed &&
400398
(trimmed.includes('/') ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lorem ipsum `src/hello.ts`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--- a/src/index.ts
2+
+++ b/src/index.ts
3+
@@ -1,3 +1,3 @@
4+
console.log("hello")
5+
-console.log("old message")
6+
+console.log("new message")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### `src/index.ts`:
2+
3+
Lorem ipsum `src/hello.ts`.
4+
5+
```diff
6+
@@ -1,3 +1,3 @@
7+
console.log("hello")
8+
-console.log("old message")
9+
+console.log("new message")

0 commit comments

Comments
 (0)