Skip to content

Commit 2b169f4

Browse files
committed
Refactor the code completion parser to correctly handle and return surrounding text alongside the completion item
1 parent 18b3b1c commit 2b169f4

4 files changed

Lines changed: 94 additions & 54 deletions

File tree

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,32 @@ describe('clipboard-parser', () => {
573573
})
574574
})
575575

576+
it('parses code completion format with surrounding text', () => {
577+
const test_case = 'code-completion-with-text'
578+
const text = load_test_case_file(test_case, `${test_case}.txt`)
579+
const result = parse_response({
580+
response: text,
581+
is_single_root_folder_workspace: true
582+
})
583+
584+
expect(result).toHaveLength(3)
585+
expect(result[0]).toMatchObject({
586+
type: 'text',
587+
content: 'Some text before.'
588+
})
589+
expect(result[1]).toMatchObject({
590+
type: 'completion',
591+
file_path: 'src/index.ts',
592+
line: 25,
593+
character: 5,
594+
content: 'console.log("completion");'
595+
})
596+
expect(result[2]).toMatchObject({
597+
type: 'text',
598+
content: 'Some text after.'
599+
})
600+
})
601+
576602
it('parses diff format with git header but no markdown code block', () => {
577603
const test_case = 'diff-with-git-header-no-markdown'
578604
const text = load_test_case_file(test_case, `${test_case}.txt`)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ export const parse_response = (params: {
7979
}): ClipboardItem[] => {
8080
const is_single_root_folder_workspace =
8181
params.is_single_root_folder_workspace ?? true
82-
const code_completion = parse_code_completion({
82+
const code_completion_items = parse_code_completion({
8383
response: params.response,
8484
is_single_root_folder_workspace
8585
})
86-
if (code_completion) {
87-
return [code_completion]
86+
if (code_completion_items && code_completion_items.length > 0) {
87+
return code_completion_items
8888
}
8989

9090
const processed_response = params.response.replace(/``````/g, '```\n```')
Lines changed: 63 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { cleanup_api_response } from '@/utils/cleanup-api-response'
2-
import { CompletionItem, extract_workspace_and_path } from '../clipboard-parser'
2+
import {
3+
CompletionItem,
4+
TextItem,
5+
extract_workspace_and_path
6+
} from '../clipboard-parser'
37

48
const extract_path_and_position = (
59
line: string
@@ -28,61 +32,71 @@ const extract_path_and_position = (
2832
export const parse_code_completion = (params: {
2933
response: string
3034
is_single_root_folder_workspace: boolean
31-
}): CompletionItem | null => {
35+
}): (CompletionItem | TextItem)[] | null => {
3236
const lines = params.response.split('\n')
33-
let in_code_block = false
34-
let first_line_of_block: string | null = null
35-
let content_lines: string[] = []
36-
37-
for (const line of lines) {
38-
if (line.trim().startsWith('```')) {
39-
if (in_code_block) {
40-
if (first_line_of_block) {
41-
const completion_info = extract_path_and_position(first_line_of_block)
42-
if (completion_info) {
43-
const { workspace_name, relative_path } =
44-
extract_workspace_and_path({
45-
raw_file_path: completion_info.path,
46-
is_single_root_folder_workspace:
47-
params.is_single_root_folder_workspace
48-
})
49-
return {
50-
type: 'completion',
51-
file_path: relative_path,
52-
content: cleanup_api_response({
53-
content: content_lines.join('\n')
54-
}),
55-
line: completion_info.line,
56-
character: completion_info.character,
57-
workspace_name
58-
}
59-
}
37+
let code_block_start_index = -1
38+
let code_block_end_index = -1
39+
40+
for (let i = 0; i < lines.length; i++) {
41+
if (lines[i].trim().startsWith('```')) {
42+
code_block_start_index = i
43+
for (let j = i + 1; j < lines.length; j++) {
44+
if (lines[j].trim().startsWith('```')) {
45+
code_block_end_index = j
46+
break
6047
}
61-
in_code_block = false
62-
first_line_of_block = null
63-
content_lines = []
64-
} else {
65-
in_code_block = true
6648
}
67-
continue
49+
break
6850
}
51+
}
6952

70-
if (in_code_block) {
71-
if (first_line_of_block === null) {
72-
first_line_of_block = line
73-
} else {
74-
content_lines.push(line)
75-
}
76-
}
53+
if (code_block_start_index === -1) {
54+
return null
7755
}
7856

79-
// Handle unclosed block at end of file
80-
if (in_code_block && first_line_of_block) {
81-
const completion_info = extract_path_and_position(first_line_of_block)
82-
if (completion_info) {
83-
// This case is not handled and will result in returning null.
84-
}
57+
if (code_block_end_index === -1) {
58+
code_block_end_index = lines.length - 1
8559
}
8660

87-
return null
61+
const first_line_of_block = lines[code_block_start_index + 1]
62+
const completion_info = extract_path_and_position(first_line_of_block)
63+
64+
if (!completion_info) {
65+
return null
66+
}
67+
68+
const results: (CompletionItem | TextItem)[] = []
69+
const text_before = lines.slice(0, code_block_start_index).join('\n').trim()
70+
if (text_before) {
71+
results.push({ type: 'text', content: text_before })
72+
}
73+
74+
const { workspace_name, relative_path } = extract_workspace_and_path({
75+
raw_file_path: completion_info.path,
76+
is_single_root_folder_workspace: params.is_single_root_folder_workspace
77+
})
78+
79+
const content_lines = lines.slice(
80+
code_block_start_index + 2,
81+
code_block_end_index
82+
)
83+
84+
results.push({
85+
type: 'completion',
86+
file_path: relative_path,
87+
content: cleanup_api_response({ content: content_lines.join('\n') }),
88+
line: completion_info.line,
89+
character: completion_info.character,
90+
workspace_name
91+
})
92+
93+
const text_after = lines
94+
.slice(code_block_end_index + 1)
95+
.join('\n')
96+
.trim()
97+
if (text_after) {
98+
results.push({ type: 'text', content: text_after })
99+
}
100+
101+
return results
88102
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export const parse_multiple_files = (params: {
294294
}
295295
backtick_nesting_level++
296296
if (
297-
(current_language === 'markdown' || current_language === 'md') &&
297+
(current_language == 'markdown' || current_language === 'md') &&
298298
backtick_nesting_level > 1
299299
) {
300300
is_markdown_container_block = true
@@ -318,7 +318,7 @@ export const parse_multiple_files = (params: {
318318
return false
319319
})()
320320
) {
321-
if (current_language === 'markdown' || current_language === 'md') {
321+
if (current_language == 'markdown' || current_language === 'md') {
322322
is_markdown_container_block = true
323323
}
324324
backtick_nesting_level++

0 commit comments

Comments
 (0)