Skip to content

Commit f1452cb

Browse files
committed
Refine clipboard parsing logic to correctly handle file paths specified in XML tags, markdown headings, or backticks immediately preceding code blocks, and remove redundant test cases
1 parent 9239dd0 commit f1452cb

10 files changed

Lines changed: 118 additions & 33 deletions

File tree

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

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ describe('clipboard-parser', () => {
6565
})
6666
})
6767

68+
it('parses file when using code-block-xml format within a markdown code block', () => {
69+
const test_case = 'code-block-xml'
70+
const text = load_test_case_file(test_case, `${test_case}.txt`)
71+
const result = parse_multiple_files({
72+
response: text,
73+
is_single_root_folder_workspace: true
74+
})
75+
76+
expect(result).toHaveLength(1)
77+
expect(result[0]).toMatchObject({
78+
type: 'file',
79+
file_path: 'src/index.ts',
80+
content: load_test_case_file(test_case, '1-file.txt')
81+
})
82+
})
83+
6884
it('parses file when using file-xml format with CDATA outside a markdown code block', () => {
6985
const test_case = 'file-xml-with-cdata'
7086
const text = load_test_case_file(test_case, `${test_case}.txt`)
@@ -574,22 +590,6 @@ describe('clipboard-parser', () => {
574590
})
575591
})
576592

577-
it('extracts file path from backticks when there are only empty intermediate lines before code block', () => {
578-
const test_case = 'path-in-backticks-with-intermediate-empty-lines'
579-
const text = load_test_case_file(test_case, `${test_case}.txt`)
580-
const result = parse_multiple_files({
581-
response: text,
582-
is_single_root_folder_workspace: true
583-
})
584-
585-
expect(result).toHaveLength(1)
586-
expect(result[0]).toMatchObject({
587-
type: 'file',
588-
file_path: 'src/main.py',
589-
content: load_test_case_file(test_case, '1-file.txt')
590-
})
591-
})
592-
593593
it('does not extract file path from backticks when there is intermediate text before code block', () => {
594594
const test_case = 'path-in-backticks-with-intermediate-text'
595595
const text = load_test_case_file(test_case, `${test_case}.txt`)
@@ -1420,6 +1420,29 @@ describe('clipboard-parser', () => {
14201420
})
14211421
})
14221422

1423+
it('parses diff format with file path specified in plain text above and inside a markdown code block', () => {
1424+
const test_case = 'diff-markdown-repeated-path-above'
1425+
const text = load_test_case_file(
1426+
test_case,
1427+
'diff-markdown-repeated-path-above.txt'
1428+
)
1429+
const result = parse_response({
1430+
response: text,
1431+
is_single_root_folder_workspace: true
1432+
})
1433+
1434+
expect(result).toHaveLength(2)
1435+
expect(result[0]).toMatchObject({
1436+
type: 'text',
1437+
content: load_test_case_file(test_case, '1-text.txt')
1438+
})
1439+
expect(result[1]).toMatchObject({
1440+
type: 'diff',
1441+
file_path: 'src/index.ts',
1442+
content: load_test_case_file(test_case, '2-file.txt')
1443+
})
1444+
})
1445+
14231446
it('parses diff with broken hunk header after git header', () => {
14241447
const test_case = 'diff-git-broken-hunk-header'
14251448
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: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -507,16 +507,60 @@ const extract_all_code_block_patches = (params: {
507507
if (patches.length > 0) {
508508
const last_item = items.length > 0 ? items[items.length - 1] : undefined
509509
if (last_item && last_item.type == 'text') {
510-
let potential_path = last_item.content.trim()
511-
if (potential_path.endsWith(':')) {
512-
potential_path = potential_path.slice(0, -1).trim()
510+
const content_lines = last_item.content.split('\n')
511+
let last_non_empty_line_index = -1
512+
let last_non_empty_line = ''
513+
for (let i = content_lines.length - 1; i >= 0; i--) {
514+
if (content_lines[i].trim() !== '') {
515+
last_non_empty_line_index = i
516+
last_non_empty_line = content_lines[i].trim()
517+
break
518+
}
513519
}
514-
const { relative_path } = extract_workspace_and_path({
515-
raw_file_path: potential_path,
516-
is_single_root_folder_workspace: params.is_single_root
517-
})
518-
if (relative_path == patches[0].file_path) {
519-
items.pop()
520+
521+
if (last_non_empty_line) {
522+
let extracted = extract_path_from_line_of_code(last_non_empty_line)
523+
524+
if (!extracted) {
525+
let potential_path = last_non_empty_line
526+
if (potential_path.endsWith(':')) {
527+
potential_path = potential_path.slice(0, -1).trim()
528+
}
529+
const backtick_match = potential_path.match(/`([^`]+)`/)
530+
if (backtick_match && backtick_match[1]) {
531+
potential_path = backtick_match[1]
532+
}
533+
534+
if (
535+
potential_path &&
536+
(potential_path.includes('/') ||
537+
potential_path.includes('\\') ||
538+
potential_path.includes('.')) &&
539+
!potential_path.endsWith('.') &&
540+
/^[a-zA-Z0-9_./@-]+$/.test(potential_path)
541+
) {
542+
extracted = potential_path
543+
}
544+
}
545+
546+
if (extracted) {
547+
const { relative_path } = extract_workspace_and_path({
548+
raw_file_path: extracted,
549+
is_single_root_folder_workspace: params.is_single_root
550+
})
551+
if (relative_path === patches[0].file_path) {
552+
const new_content = content_lines
553+
.slice(0, last_non_empty_line_index)
554+
.join('\n')
555+
.trim()
556+
557+
if (new_content) {
558+
last_item.content = new_content
559+
} else {
560+
items.pop()
561+
}
562+
}
563+
}
520564
}
521565
}
522566
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { parse_file_content_only } from './file-content-only-parser'
1010
const extract_file_path_from_xml = (
1111
line: string
1212
): { tagName: string; path: string } | null => {
13-
const match = line.match(/<(\w+)\s+path=["']([^"']+)["']/)
13+
const match = line.match(/<([\w-]+)\s+path=["']([^"']+)["']/)
1414
if (match && match[1] && match[2]) {
1515
return { tagName: match[1], path: match[2] }
1616
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("hello")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
```typescript
2+
<code-block path="src/index.ts">
3+
console.log("hello")
4+
</code-block>
5+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lorem ipsum.
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,12 @@
1+
Lorem ipsum.
2+
3+
# `src/index.ts`:
4+
5+
```diff
6+
--- a/src/index.ts
7+
+++ b/src/index.ts
8+
@@ -1,3 +1,3 @@
9+
console.log("hello")
10+
-console.log("old message")
11+
+console.log("new message")
12+
```

‎packages/vscode/src/commands/apply-chat-response-command/utils/clipboard-parser/test-cases/path-in-backticks-with-intermediate-empty-lines/1-file.txt‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎packages/vscode/src/commands/apply-chat-response-command/utils/clipboard-parser/test-cases/path-in-backticks-with-intermediate-empty-lines/path-in-backticks-with-intermediate-empty-lines.txt‎

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)