Skip to content

Commit 7a1e42f

Browse files
committed
Enhance file patch application and rename handling by propagating workspace context and improving path resolution
1 parent 67d5104 commit 7a1e42f

4 files changed

Lines changed: 81 additions & 27 deletions

File tree

apps/editor/src/commands/apply-chat-response-command/apply-chat-response-command.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@ export const apply_chat_response_command = (params: {
9191

9292
const is_single_root_folder_workspace =
9393
(vscode.workspace.workspaceFolders?.length ?? 0) <= 1
94+
9495
const clipboard_items = parse_response({
9596
response: chat_response,
9697
is_single_root_folder_workspace
9798
})
99+
98100
if (resolve_fn) {
99101
const history = params.panel_provider.response_history
100102

apps/editor/src/commands/apply-chat-response-command/handlers/diff-handler.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { OriginalFileState } from '../types/original-file-state'
77
import { create_safe_path } from '@/utils/path-sanitizer'
88
import { apply_diff } from '../utils/edit-formats/diffs'
99
import { remove_directory_if_empty } from '../utils/file-operations'
10+
import { DiffItem } from '../utils/clipboard-parser'
1011

1112
export const sanitize_patch_content = (
1213
patch_content: string,
@@ -130,20 +131,28 @@ const parse_patch_header = (
130131
}
131132

132133
export const extract_file_paths_from_patch = (
133-
patch_content: string
134+
patch_content: string,
135+
fallback_patch?: DiffItem
134136
): string[] => {
135137
const { from_path, to_path } = parse_patch_header(patch_content)
136138
const paths = new Set<string>()
137139
if (from_path) paths.add(from_path)
138140
if (to_path) paths.add(to_path)
141+
142+
if (paths.size === 0 && fallback_patch) {
143+
if (fallback_patch.file_path) paths.add(fallback_patch.file_path)
144+
if (fallback_patch.new_file_path) paths.add(fallback_patch.new_file_path)
145+
}
139146
return Array.from(paths)
140147
}
141148

142149
export const store_original_file_states = async (
143150
patch_content: string,
144-
workspace_path: string
151+
workspace_path: string,
152+
workspace_name?: string,
153+
fallback_patch?: DiffItem
145154
): Promise<OriginalFileState[]> => {
146-
const file_paths = extract_file_paths_from_patch(patch_content)
155+
const file_paths = extract_file_paths_from_patch(patch_content, fallback_patch)
147156
const original_states: OriginalFileState[] = []
148157

149158
for (const file_path of file_paths) {
@@ -164,7 +173,7 @@ export const store_original_file_states = async (
164173
original_states.push({
165174
file_path,
166175
content,
167-
workspace_name: path.basename(workspace_path)
176+
workspace_name
168177
})
169178
} catch (error) {
170179
Logger.error({
@@ -178,7 +187,7 @@ export const store_original_file_states = async (
178187
file_path,
179188
content: '',
180189
file_state: 'new',
181-
workspace_name: path.basename(workspace_path)
190+
workspace_name
182191
})
183192
}
184193
}
@@ -292,13 +301,15 @@ const process_modified_files = async (
292301

293302
const handle_new_file_patch = async (
294303
patch_content: string,
295-
workspace_path: string
304+
workspace_path: string,
305+
workspace_name?: string,
306+
fallback_patch?: DiffItem
296307
): Promise<{
297308
success: boolean
298309
original_states?: OriginalFileState[]
299310
diff_application_method?: 'recount' | 'search_and_replace'
300311
}> => {
301-
const file_paths = extract_file_paths_from_patch(patch_content)
312+
const file_paths = extract_file_paths_from_patch(patch_content, fallback_patch)
302313
if (file_paths.length != 1) {
303314
Logger.error({
304315
function_name: 'handle_new_file_patch',
@@ -323,7 +334,9 @@ const handle_new_file_patch = async (
323334
// `store_original_file_states` will correctly identify this as a new file.
324335
const original_states = await store_original_file_states(
325336
patch_content,
326-
workspace_path
337+
workspace_path,
338+
workspace_name,
339+
fallback_patch
327340
)
328341

329342
try {
@@ -364,13 +377,15 @@ const handle_new_file_patch = async (
364377

365378
const handle_deleted_file_patch = async (
366379
patch_content: string,
367-
workspace_path: string
380+
workspace_path: string,
381+
workspace_name?: string,
382+
fallback_patch?: DiffItem
368383
): Promise<{
369384
success: boolean
370385
original_states?: OriginalFileState[]
371386
diff_application_method?: 'recount' | 'search_and_replace'
372387
}> => {
373-
const file_paths = extract_file_paths_from_patch(patch_content)
388+
const file_paths = extract_file_paths_from_patch(patch_content, fallback_patch)
374389
if (file_paths.length != 1) {
375390
Logger.error({
376391
function_name: 'handle_deleted_file_patch',
@@ -395,7 +410,9 @@ const handle_deleted_file_patch = async (
395410

396411
const original_states = await store_original_file_states(
397412
patch_content,
398-
workspace_path
413+
workspace_path,
414+
workspace_name,
415+
fallback_patch
399416
)
400417

401418
try {
@@ -480,7 +497,9 @@ const process_diff = async (params: {
480497

481498
export const apply_git_patch = async (
482499
patch_content: string,
483-
workspace_path: string
500+
workspace_path: string,
501+
workspace_name?: string,
502+
patch?: DiffItem
484503
): Promise<{
485504
success: boolean
486505
original_states?: OriginalFileState[]
@@ -489,21 +508,23 @@ export const apply_git_patch = async (
489508
const patch_info = parse_patch_header(patch_content, workspace_path)
490509

491510
if (patch_info.is_new) {
492-
return handle_new_file_patch(patch_content, workspace_path)
511+
return handle_new_file_patch(patch_content, workspace_path, workspace_name, patch)
493512
}
494513

495514
if (patch_info.is_deleted) {
496-
return handle_deleted_file_patch(patch_content, workspace_path)
515+
return handle_deleted_file_patch(patch_content, workspace_path, workspace_name, patch)
497516
}
498517

499518
let closed_files: vscode.Uri[] = []
500519
let original_states: OriginalFileState[] | undefined
501520

502521
try {
503-
const file_paths = extract_file_paths_from_patch(patch_content)
522+
const file_paths = extract_file_paths_from_patch(patch_content, patch)
504523
original_states = await store_original_file_states(
505524
patch_content,
506-
workspace_path
525+
workspace_path,
526+
workspace_name,
527+
patch
507528
)
508529

509530
closed_files = await close_files_in_all_editor_groups(
@@ -557,6 +578,9 @@ export const apply_git_patch = async (
557578
data: { error: last_error }
558579
})
559580
try {
581+
if (file_paths.length == 0) {
582+
throw new Error('No file paths could be extracted from patch')
583+
}
560584
const file_path_safe = create_safe_path(workspace_path, file_paths[0])
561585
if (file_path_safe == null) throw new Error('File path is null')
562586

apps/editor/src/commands/apply-chat-response-command/response-processor.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,13 @@ export const process_chat_response = async (params: {
277277
const key = `${patch.workspace_name || ''}:${patch.file_path}`
278278
rename_map.set(key, {
279279
new_path: patch.new_file_path,
280-
new_workspace: patch.new_workspace_name
280+
new_workspace: patch.new_workspace_name || patch.workspace_name
281281
})
282282
}
283283
})
284284

285-
const set_new_paths_in_original_states = (states: OriginalFileState[]) => {
286-
if (!rename_map.size) return
285+
const set_new_paths_in_original_states = (states: OriginalFileState[]): OriginalFileState[] => {
286+
if (!rename_map.size) return states
287287
states.forEach((state) => {
288288
const key = `${state.workspace_name || ''}:${state.file_path}`
289289
if (rename_map.has(key)) {
@@ -292,6 +292,21 @@ export const process_chat_response = async (params: {
292292
state.new_workspace_name = rename_info.new_workspace
293293
}
294294
})
295+
296+
const target_paths = new Set<string>()
297+
rename_map.forEach((val) => {
298+
target_paths.add(`${val.new_workspace || ''}:${val.new_path}`)
299+
})
300+
301+
return states.filter((state) => {
302+
if (state.file_state == 'new') {
303+
const key = `${state.workspace_name || ''}:${state.file_path}`
304+
if (target_paths.has(key)) {
305+
return false
306+
}
307+
}
308+
return true
309+
})
295310
}
296311

297312
const workspace_map = new Map<string, string>()
@@ -324,7 +339,7 @@ export const process_chat_response = async (params: {
324339
patch.content,
325340
patch.workspace_name
326341
)
327-
const result = await apply_git_patch(sanitized_patch_content, workspace_path)
342+
const result = await apply_git_patch(sanitized_patch_content, workspace_path, patch.workspace_name, patch)
328343

329344
if (result.success) {
330345
if (result.diff_application_method && result.original_states) {
@@ -360,7 +375,7 @@ export const process_chat_response = async (params: {
360375
}
361376

362377
if (all_original_states.length > 0) {
363-
set_new_paths_in_original_states(all_original_states)
378+
all_original_states = set_new_paths_in_original_states(all_original_states)
364379
await apply_file_relocations(all_original_states)
365380
update_undo_button_state({
366381
context: params.context,

apps/editor/src/commands/apply-chat-response-command/utils/file-operations.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,12 +333,25 @@ export const apply_file_relocations = async (
333333
new_workspace_root = workspace_map.get(state.new_workspace_name)!
334334
}
335335

336-
const success = await relocate_file({
337-
old_path: state.file_path,
338-
new_path: state.new_file_path,
339-
old_workspace_root: workspace_root,
340-
new_workspace_root: new_workspace_root
341-
})
336+
const old_safe_path = create_safe_path(workspace_root, state.file_path)
337+
const new_safe_path = create_safe_path(new_workspace_root, state.new_file_path)
338+
339+
if (!old_safe_path || !new_safe_path) continue
340+
341+
const old_exists = await uri_exists(vscode.Uri.file(old_safe_path))
342+
const new_exists = await uri_exists(vscode.Uri.file(new_safe_path))
343+
344+
let success = false
345+
if (old_exists) {
346+
success = await relocate_file({
347+
old_path: state.file_path,
348+
new_path: state.new_file_path,
349+
old_workspace_root: workspace_root,
350+
new_workspace_root: new_workspace_root
351+
})
352+
} else if (new_exists) {
353+
success = true
354+
}
342355

343356
if (success) {
344357
state.file_path_to_restore = state.file_path

0 commit comments

Comments
 (0)