Skip to content

Commit cf0e5e0

Browse files
committed
Replace XML output with markdown formatting and fix placeholder regex escaping for consistent symbol replacement
1 parent 496f399 commit cf0e5e0

3 files changed

Lines changed: 95 additions & 84 deletions

File tree

‎packages/vscode/src/utils/replace-saved-context-placeholder.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,21 @@ export const replace_saved_context_placeholder = async (params: {
168168
}
169169

170170
replacement_text = context_text
171-
? `\n<files name="${name}">\n${context_text}</files>\n`
171+
? `\n<files name="${name}">\n${context_text}</files>`
172172
: ''
173173
}
174174
replacements.set(full_match, replacement_text)
175175
}
176176

177177
for (const [placeholder, replacement] of replacements.entries()) {
178-
result_instruction = result_instruction.replaceAll(placeholder, replacement)
178+
const escaped_placeholder = placeholder.replace(
179+
/[.*+?^${}()|[\]\\]/g,
180+
'\\$&'
181+
)
182+
result_instruction = result_instruction.replace(
183+
new RegExp(`\\s*${escaped_placeholder}\\s*`, 'g'),
184+
replacement
185+
)
179186
}
180187

181188
return result_instruction

‎packages/vscode/src/views/panel/backend/utils/replace-git-symbols.ts‎

Lines changed: 85 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,19 @@ import { WorkspaceProvider } from '@/context/providers/workspace-provider'
77
import { Logger } from '@shared/utils/logger'
88
import { dictionary } from '@shared/constants/dictionary'
99

10-
const build_changes_xml = (
10+
const build_changes_markdown = (
1111
diff: string,
1212
cwd: string,
13-
workspace_provider: WorkspaceProvider,
14-
is_no_context_web_mode?: boolean
13+
diff_base: string,
14+
branch_name: string
1515
): string => {
1616
// Split diff into per-file sections. Each section starts with 'diff --git '.
1717
const file_diffs = diff.split(/^diff --git /m).filter((d) => d.trim() != '')
18-
1918
if (file_diffs.length == 0) {
2019
return ''
2120
}
2221

2322
let changes_content = ''
24-
const checked_files = new Set(workspace_provider.get_checked_files())
2523

2624
for (const file_diff_content of file_diffs) {
2725
const full_file_diff = 'diff --git ' + file_diff_content
@@ -49,52 +47,37 @@ const build_changes_xml = (
4947
}
5048

5149
if (file_path) {
52-
changes_content += `<change path="${file_path}">\n`
53-
changes_content += `<diff>\n<![CDATA[\n${full_file_diff}\n]]>\n</diff>\n`
54-
55-
const absolute_path = path.join(cwd, file_path)
56-
if (!is_no_context_web_mode && checked_files.has(absolute_path)) {
57-
const workspace_root =
58-
workspace_provider.get_workspace_root_for_file(absolute_path)
59-
let display_path: string
60-
if (workspace_root) {
61-
const relative_path = path
62-
.relative(workspace_root, absolute_path)
63-
.replace(/\\/g, '/')
64-
if (workspace_provider.getWorkspaceRoots().length > 1) {
65-
const workspace_name =
66-
workspace_provider.get_workspace_name(workspace_root)
67-
display_path = `${workspace_name}/${relative_path}`
68-
} else {
69-
display_path = relative_path
70-
}
71-
} else {
72-
display_path = file_path.replace(/\\/g, '/')
73-
}
74-
changes_content += `<file path="${display_path}" />\n`
75-
} else {
76-
let file_content = ''
50+
changes_content += `\n\n### File: \`${file_path}\`\n\n`
51+
52+
let file_content = ''
53+
try {
54+
// Get the file content from the git revision we're diffing against.
55+
file_content = execSync(`git show ${diff_base}:"./${file_path}"`, {
56+
cwd,
57+
encoding: 'utf-8',
58+
stdio: ['pipe', 'pipe', 'ignore'] // Prevent git errors from crashing (e.g., file not on branch)
59+
})
60+
} catch (e) {
61+
// File likely did not exist on the branch (i.e., it's a new file).
62+
// In this case, the original content is correctly an empty string.
7763
if (!is_deleted) {
78-
try {
79-
file_content = fs.readFileSync(absolute_path, 'utf-8')
80-
} catch (e) {
81-
if ((e as NodeJS.ErrnoException).code !== 'ENOENT') {
82-
Logger.error({
83-
function_name: 'build_changes_xml',
84-
message: `Could not read file for diff: ${absolute_path}`,
85-
data: e
86-
})
87-
}
88-
}
64+
Logger.warn({
65+
function_name: 'build_changes_markdown',
66+
message: `Could not get file content from git base ${diff_base} for path ${file_path}. Assuming it's a new file.`,
67+
data: e
68+
})
8969
}
90-
changes_content += `<file>\n<![CDATA[\n${file_content}\n]]>\n</file>\n`
9170
}
92-
changes_content += `</change>\n`
71+
if (file_content) {
72+
const lang = path.extname(file_path).slice(1)
73+
changes_content += `The original state of the file for reference:\n\n\`\`\`${lang}\n${file_content}\n\`\`\`\n\n`
74+
}
75+
changes_content += `**New changes:**\n\n\`\`\`diff\n${full_file_diff}\`\`\`\n`
9376
}
9477
}
9578

9679
if (changes_content) {
97-
return `\n<changes>\n${changes_content}</changes>\n`
80+
return `\n\n# Changes against ${branch_name} branch${changes_content}\n---\n\n`
9881
}
9982
return ''
10083
}
@@ -115,9 +98,16 @@ export const replace_changes_symbol = async (params: {
11598
const branch_spec = matches[1]
11699

117100
if (params.after_context) {
101+
let branch_name = branch_spec
102+
const multi_root_match = branch_spec.match(/^([^/]+)\/(.+)$/)
103+
104+
if (multi_root_match) {
105+
branch_name = multi_root_match[2]
106+
}
107+
118108
return params.instruction.replace(
119109
new RegExp(`#Changes:${branch_spec}`, 'g'),
120-
'<changes/>'
110+
`(Changes against ${branch_name} branch)`
121111
)
122112
}
123113

@@ -151,18 +141,24 @@ export const replace_changes_symbol = async (params: {
151141
}
152142

153143
try {
154-
// Get current branch name
155144
const current_branch = execSync('git rev-parse --abbrev-ref HEAD', {
156145
cwd: target_folder.uri.fsPath
157146
})
158147
.toString()
159148
.trim()
160149

161-
// If comparing to same branch, use merge-base to show changes since branch point
162-
const diff_command =
163-
current_branch == branch_name
164-
? `git diff $(git merge-base HEAD origin/${branch_name})`
165-
: `git diff ${branch_name}`
150+
let diff_base: string
151+
if (current_branch == branch_name) {
152+
// If comparing to same branch, use merge-base to show changes since branch point
153+
diff_base = execSync(`git merge-base HEAD origin/${branch_name}`, {
154+
cwd: target_folder.uri.fsPath
155+
})
156+
.toString()
157+
.trim()
158+
} else {
159+
diff_base = branch_name
160+
}
161+
const diff_command = `git diff ${diff_base}`
166162
const diff = execSync(diff_command, {
167163
cwd: target_folder.uri.fsPath
168164
}).toString()
@@ -180,14 +176,14 @@ export const replace_changes_symbol = async (params: {
180176
)
181177
}
182178

183-
const replacement_text = build_changes_xml(
179+
const replacement_text = build_changes_markdown(
184180
diff,
185181
target_folder.uri.fsPath,
186-
params.workspace_provider,
187-
params.is_no_context_web_mode
182+
diff_base,
183+
branch_name
188184
)
189185
return params.instruction.replace(
190-
new RegExp(`#Changes:${branch_spec}`, 'g'),
186+
new RegExp(`\\s*#Changes:${branch_spec}\\s*`, 'g'),
191187
replacement_text
192188
)
193189
} catch (error) {
@@ -221,18 +217,24 @@ export const replace_changes_symbol = async (params: {
221217
}
222218

223219
try {
224-
// Get current branch name
225220
const current_branch = execSync('git rev-parse --abbrev-ref HEAD', {
226221
cwd: repository.rootUri.fsPath
227222
})
228223
.toString()
229224
.trim()
230225

231-
// If comparing to same branch, use merge-base to show changes since branch point
232-
const diff_command =
233-
current_branch == branch_name
234-
? `git diff $(git merge-base HEAD origin/${branch_name})`
235-
: `git diff ${branch_name}`
226+
let diff_base: string
227+
if (current_branch == branch_name) {
228+
// If comparing to same branch, use merge-base to show changes since branch point
229+
diff_base = execSync(`git merge-base HEAD origin/${branch_name}`, {
230+
cwd: repository.rootUri.fsPath
231+
})
232+
.toString()
233+
.trim()
234+
} else {
235+
diff_base = branch_name
236+
}
237+
const diff_command = `git diff ${diff_base}`
236238
const diff = execSync(diff_command, {
237239
cwd: repository.rootUri.fsPath
238240
}).toString()
@@ -249,14 +251,14 @@ export const replace_changes_symbol = async (params: {
249251
)
250252
}
251253

252-
const replacement_text = build_changes_xml(
254+
const replacement_text = build_changes_markdown(
253255
diff,
254256
repository.rootUri.fsPath,
255-
params.workspace_provider,
256-
params.is_no_context_web_mode
257+
diff_base,
258+
branch_name
257259
)
258260
return params.instruction.replace(
259-
new RegExp(`#Changes:${branch_name}`, 'g'),
261+
new RegExp(`\\s*#Changes:${branch_name}\\s*`, 'g'),
260262
replacement_text
261263
)
262264
} catch (error) {
@@ -276,7 +278,7 @@ export const replace_changes_symbol = async (params: {
276278
}
277279
}
278280

279-
const build_commit_changes_xml = (
281+
const build_commit_changes_markdown = (
280282
diff: string,
281283
cwd: string,
282284
commit_hash: string,
@@ -325,25 +327,27 @@ const build_commit_changes_xml = (
325327
})
326328
} catch (e) {
327329
Logger.error({
328-
function_name: 'build_commit_changes_xml',
330+
function_name: 'build_commit_changes_markdown',
329331
message: `Could not read file for diff from commit: ${file_path}`,
330332
data: e
331333
})
332334
}
333335
}
334336

335-
changes_content += `<change path="${file_path}">\n`
336-
changes_content += `<diff>\n<![CDATA[\n${full_file_diff}\n]]>\n</diff>\n`
337-
changes_content += `<file>\n<![CDATA[\n${file_content}\n]]>\n</file>\n`
338-
changes_content += `</change>\n`
337+
changes_content += `### File: \`${file_path}\`\n\n`
338+
changes_content += `**Changes:**\n\n\`\`\`diff\n${full_file_diff}\`\`\`\n`
339+
if (file_content) {
340+
const lang = path.extname(file_path).slice(1)
341+
changes_content += `\nFull file for reference:\n\n\`\`\`${lang}\n${file_content}\n\`\`\`\n`
342+
}
339343
}
340344
}
341345

342346
if (changes_content) {
343-
const message_attribute = commit_message
344-
? ` message="${commit_message.replace(/"/g, '&quot;')}"`
347+
const message_section = commit_message
348+
? `**Message:** ${commit_message}\n\n`
345349
: ''
346-
return `\n<commit${message_attribute}>\n<changes>\n${changes_content}</changes>\n</commit>\n`
350+
return `\n\n# Commit\n\n${message_section}${changes_content}\n---\n\n`
347351
}
348352
return ''
349353
}
@@ -356,11 +360,9 @@ export const replace_commit_symbol = async (params: {
356360
if (params.after_context) {
357361
return params.instruction.replace(
358362
regex,
359-
(_match, _folder, _hash, message) => {
360-
const message_attr = message
361-
? ` message="${message.replace(/"/g, '&quot;')}"`
362-
: ''
363-
return `<commit${message_attr}/>`
363+
(_match, _folder_name, _commit_hash, commit_message) => {
364+
if (commit_message) return `(Commit: ${commit_message})`
365+
return '(Commit)'
364366
}
365367
)
366368
}
@@ -404,14 +406,16 @@ export const replace_commit_symbol = async (params: {
404406
continue
405407
}
406408

407-
const replacement_text = build_commit_changes_xml(
409+
const replacement_text = build_commit_changes_markdown(
408410
diff,
409411
target_folder.uri.fsPath,
410412
commit_hash,
411413
commit_message
412414
)
413415
result_instruction = result_instruction.replace(
414-
full_match,
416+
new RegExp(
417+
`\\s*${full_match.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*`
418+
),
415419
replacement_text
416420
)
417421
} catch (error) {

‎packages/vscode/src/views/panel/backend/utils/replace-selection-symbol.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const replace_selection_placeholder = (instruction: string): string => {
1919
const document = active_editor.document
2020
const current_file_path = vscode.workspace.asRelativePath(document.uri)
2121

22-
const replacement_text = `\n<fragment path="${current_file_path}">\n<![CDATA[\n${selected_text}\n]]>\n</fragment>\n`
22+
const replacement_text = `\n<fragment path="${current_file_path}">\n<![CDATA[\n${selected_text}\n]]>\n</fragment>`
2323

2424
return instruction.replace(/\s*#Selection\s*/g, replacement_text)
2525
}

0 commit comments

Comments
 (0)