Skip to content

Commit 6f395f7

Browse files
committed
Improve handling of in-preview out-of-response file edits
- create `apps/editor/src/commands/apply-response-command/response-processor`, inside place `apps/editor/src/commands/apply-response-command/response-processor.ts` and handlers - Extract the tab group capture and restoration logic (SavedTabGroups and restore_tab_groups) from apps/editor/src/commands/apply-response-command/apply-response-command.ts into a dedicated utility file utils/tab-group-manager.ts and import it back. - Extract the workspace map creation and root resolution logic from `apply-response-command.ts` into a reusable util - checkpoints related logic should be held by `apps/editor/src/features/checkpoints`, not `apps/editor/src/commands/apply-response-command` - Extract the inline patch-repair processing logic from `apply-response-command.ts` into a new handler function inside `apps/editor/src/commands/apply-response-command/response-processor/handlers/patch-repair-handler.ts` and update the main command to call it. - Refactor `apps/editor/src/commands/apply-response-command/apply-response-command.ts` by extracting the `preview_data.original_states` loop that builds `files_for_history` and calculates diff stats into a dedicated utility function in `apps/editor/src/commands/apply-response-command/utils/preview/build-history-files.ts`. - Regarding response previewing: files outside of the original parsed response that were added due modification, should be removed when modification is reverted, so that we don't see +0 -0 items. Make sure restoring response from history keeps the file detail it was added outside the original response - we need to be able to continue removing it from the list if it becomes +0 -0. - don't show 'apply with patch repair' on files that were 'added in preview' ├── apps │ └── editor │ └── src │ ├── commands │ │ └── apply-response-command │ │ ├── apply-response-command.ts │ │ ├── response-processor │ │ │ ├── handlers │ │ │ │ ├── diff-handler.ts │ │ │ │ ├── fast-replace-handler.ts │ │ │ │ ├── patch-repair-handler.ts │ │ │ │ ├── restore-preview-handler.ts │ │ │ │ ├── search-replace-handler.ts │ │ │ │ └── truncated-handler.ts │ │ │ ├── index.ts │ │ │ └── response-processor.ts │ │ ├── types │ │ │ └── original-file-state.ts │ │ └── utils │ │ ├── file-checks.ts │ │ ├── file-operations │ │ │ ├── apply-file-relocations.ts │ │ │ ├── cleanup-rename-source.ts │ │ │ ├── close-file-tabs.ts │ │ │ ├── create-file-if-needed.ts │ │ │ ├── get-rename-source-info.ts │ │ │ ├── handle-deleted-file-item.ts │ │ │ ├── index.ts │ │ │ ├── read-rename-source-file.ts │ │ │ ├── relocate-file.ts │ │ │ ├── remove-directory-if-empty.ts │ │ │ ├── undo-files.ts │ │ │ └── uri-exists.ts │ │ ├── preview │ │ │ ├── build-history-files.ts │ │ │ ├── diff-utils.ts │ │ │ ├── file-preparer.ts │ │ │ ├── index.ts │ │ │ ├── preview.ts │ │ │ ├── temp-file-manager.ts │ │ │ ├── types.ts │ │ │ ├── virtual-document-provider.ts │ │ │ ├── vscode-ui.ts │ │ │ └── workspace-listener.ts │ │ ├── preview-handler.ts │ │ ├── response-parser │ │ │ ├── index.ts │ │ │ ├── parsers │ │ │ │ └── diff-parser │ │ │ │ ├── diff-parser.ts │ │ │ │ ├── helpers │ │ │ │ │ └── block-utils.ts │ │ │ │ └── test │ │ │ │ └── diff-parser.spec.ts │ │ │ └── response-parser.ts │ │ ├── state-manager.ts │ │ ├── tab-group-manager.ts │ │ └── workspace.ts │ ├── features │ │ └── checkpoints │ │ ├── actions │ │ │ ├── accept-checkpoint.ts │ │ │ ├── create-checkpoint.ts │ │ │ ├── delete-checkpoint.ts │ │ │ ├── get-checkpoints.ts │ │ │ └── index.ts │ │ ├── types │ │ │ ├── checkpoint.ts │ │ │ └── index.ts │ │ └── utils │ │ ├── copy-optimised-recursively.ts │ │ ├── get-checkpoint-path.ts │ │ ├── get-incremented-description.ts │ │ ├── git-utils.ts │ │ └── index.ts │ ├── services │ │ └── websocket-manager.ts │ └── views │ └── prompt │ ├── backend │ │ ├── message-handlers │ │ │ ├── handle-cancel-intelligent-update-file-in-preview.ts │ │ │ ├── handle-discard-user-changes-in-preview.ts │ │ │ ├── handle-focus-on-file-in-preview.ts │ │ │ ├── handle-patch-repair.ts │ │ │ ├── handle-preview-generated-code.ts │ │ │ ├── handle-response-preview.ts │ │ │ └── handle-toggle-file-in-preview.ts │ │ └── prompt-view-provider.ts │ ├── frontend │ │ ├── Main │ │ │ ├── Main.tsx │ │ │ └── MainView │ │ │ └── MainView.tsx │ │ ├── Prompt.tsx │ │ └── hooks │ │ ├── use-preview-manager.ts │ │ └── use-response-history.ts │ └── types │ └── messages.ts └── packages ├── shared │ └── src │ └── types │ ├── file-in-preview.ts │ └── response-history-item.ts └── ui └── src └── components └── editor └── prompt ├── ResponsePreview │ ├── ResponsePreview.module.scss │ ├── ResponsePreview.tsx │ ├── components │ │ ├── FileItem │ │ │ ├── FileItem.module.scss │ │ │ ├── FileItem.tsx │ │ │ └── index.ts │ │ ├── InlineFileItem │ │ │ ├── InlineFileItem.module.scss │ │ │ ├── InlineFileItem.tsx │ │ │ └── index.ts │ │ ├── TextItem │ │ │ ├── TextItem.module.scss │ │ │ ├── TextItem.tsx │ │ │ └── index.ts │ │ └── index.ts │ └── index.ts ├── ResponsePreviewFooter │ ├── ResponsePreviewFooter.module.scss │ ├── ResponsePreviewFooter.tsx │ └── index.ts └── Responses ├── Responses.stories.tsx └── Responses.tsx
1 parent 8891c3b commit 6f395f7

28 files changed

Lines changed: 811 additions & 583 deletions

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

Lines changed: 29 additions & 320 deletions
Large diffs are not rendered by default.

apps/editor/src/commands/apply-response-command/handlers/diff-handler.ts renamed to apps/editor/src/commands/apply-response-command/response-processor/handlers/diff-handler.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import * as path from 'path'
33
import * as fs from 'fs'
44
import { exec } from 'child_process'
55
import { Logger } from '@shared/utils/logger'
6-
import { OriginalFileState } from '../types/original-file-state'
6+
import { OriginalFileState } from '../../types/original-file-state'
77
import { create_safe_path } from '@/utils/path-sanitizer'
8-
import { apply_diff } from '../../../utils/changes-integration/diff-processor'
9-
import { remove_directory_if_empty } from '../utils/file-operations'
10-
import { DiffItem } from '../utils/response-parser'
8+
import { apply_diff } from '../../../../utils/changes-integration/diff-processor'
9+
import { remove_directory_if_empty } from '../../utils/file-operations'
10+
import { DiffItem } from '../../utils/response-parser'
1111

1212
export const sanitize_patch_content = (
1313
patch_content: string,

apps/editor/src/commands/apply-response-command/handlers/fast-replace-handler.ts renamed to apps/editor/src/commands/apply-response-command/response-processor/handlers/fast-replace-handler.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import * as fs from 'fs'
44
import { Logger } from '@shared/utils/logger'
55
import { create_safe_path, sanitize_file_name } from '@/utils/path-sanitizer'
66
import { t } from '@/i18n'
7-
import { FileItem } from '../utils/response-parser'
7+
import { FileItem } from '../../utils/response-parser'
88
import { OriginalFileState } from '@/commands/apply-response-command/types/original-file-state'
9+
import {
10+
get_workspace_map_and_default,
11+
resolve_workspace_root
12+
} from '../../utils/workspace'
913
import {
1014
cleanup_rename_source,
1115
handle_deleted_file_item,
1216
get_rename_source_info
13-
} from '../utils/file-operations'
17+
} from '../../utils/file-operations'
1418

1519
export const handle_fast_replace = async (params: {
1620
files: FileItem[]
@@ -39,23 +43,16 @@ export const handle_fast_replace = async (params: {
3943
return { success: false }
4044
}
4145

42-
const workspace_map = new Map<string, string>()
43-
vscode.workspace.workspaceFolders.forEach((folder) => {
44-
workspace_map.set(folder.name, folder.uri.fsPath)
45-
})
46-
47-
const default_workspace = vscode.workspace.workspaceFolders[0].uri.fsPath
46+
const { workspace_map, default_workspace } = get_workspace_map_and_default()
4847

4948
for (const file of params.files) {
50-
let workspace_root = default_workspace
51-
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
52-
workspace_root = workspace_map.get(file.workspace_name)!
53-
} else if (file.workspace_name) {
54-
Logger.warn({
55-
function_name: 'handle_fast_replace',
56-
message: `Workspace '${file.workspace_name}' not found for file '${file.file_path}'. Using default.`
57-
})
58-
}
49+
const workspace_root = resolve_workspace_root({
50+
workspace_name: file.workspace_name,
51+
workspace_map,
52+
default_workspace,
53+
file_path: file.file_path,
54+
function_name: 'handle_fast_replace'
55+
})
5956

6057
const sanitized_path = sanitize_file_name(file.file_path)
6158

@@ -98,10 +95,11 @@ export const handle_fast_replace = async (params: {
9895
for (let i = 0; i < total_files; i++) {
9996
params.on_progress(Math.round((i / total_files) * 100))
10097
const file = safe_files[i]
101-
let workspace_root = default_workspace
102-
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
103-
workspace_root = workspace_map.get(file.workspace_name)!
104-
}
98+
const workspace_root = resolve_workspace_root({
99+
workspace_name: file.workspace_name,
100+
workspace_map,
101+
default_workspace
102+
})
105103

106104
const safe_path = create_safe_path(workspace_root, file.file_path)
107105

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as vscode from 'vscode'
2+
import { t } from '@/i18n'
3+
import { create_safe_path } from '@/utils/path-sanitizer'
4+
import { PatchRepairItem } from '../../utils/response-parser'
5+
import { PromptViewProvider } from '@/views/prompt/backend/prompt-view-provider'
6+
import { WorkspaceProvider } from '@/context/providers/workspace/workspace-provider'
7+
import { set_file_applied_with_patch_repair } from '../../utils/preview/workspace-listener'
8+
import {
9+
get_workspace_map_and_default,
10+
resolve_workspace_root
11+
} from '../../utils/workspace'
12+
13+
export const handle_patch_repair = async (params: {
14+
patch_items: PatchRepairItem[]
15+
prompt_view_provider: PromptViewProvider
16+
workspace_provider: WorkspaceProvider
17+
}): Promise<void> => {
18+
const { workspace_map, default_workspace } = get_workspace_map_and_default()
19+
20+
params.workspace_provider.pause_file_watcher()
21+
try {
22+
for (const patch_item of params.patch_items) {
23+
const workspace_root = resolve_workspace_root({
24+
workspace_name: patch_item.workspace_name,
25+
workspace_map,
26+
default_workspace
27+
})
28+
const safe_path = create_safe_path(workspace_root, patch_item.file_path)
29+
if (safe_path) {
30+
await vscode.workspace.fs.writeFile(
31+
vscode.Uri.file(safe_path),
32+
Buffer.from(patch_item.content, 'utf8')
33+
)
34+
if (set_file_applied_with_patch_repair) {
35+
set_file_applied_with_patch_repair({
36+
file_path: patch_item.file_path,
37+
workspace_name: patch_item.workspace_name
38+
})
39+
}
40+
}
41+
}
42+
43+
params.prompt_view_provider.send_message({
44+
command: 'SHOW_AUTO_CLOSING_MODAL',
45+
title: t('command.apply-response-command.success.patched-successfully')
46+
})
47+
} finally {
48+
params.workspace_provider.resume_file_watcher()
49+
}
50+
}

apps/editor/src/commands/apply-response-command/handlers/restore-preview-handler.ts renamed to apps/editor/src/commands/apply-response-command/response-processor/handlers/restore-preview-handler.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ import * as fs from 'fs'
44
import { Logger } from '@shared/utils/logger'
55
import { create_safe_path } from '@/utils/path-sanitizer'
66
import { t } from '@/i18n'
7-
import { OriginalFileState } from '../types/original-file-state'
7+
import { OriginalFileState } from '../../types/original-file-state'
88
import { FileInPreview } from '@shared/types/file-in-preview'
9-
import { remove_directory_if_empty } from '../utils/file-operations'
9+
import {
10+
get_workspace_map_and_default,
11+
resolve_workspace_root
12+
} from '../../utils/workspace'
13+
import { remove_directory_if_empty } from '../../utils/file-operations'
1014

1115
export const handle_restore_preview = async (
1216
files: FileInPreview[]
@@ -31,24 +35,18 @@ export const handle_restore_preview = async (
3135
return { success: false }
3236
}
3337

34-
const workspace_map = new Map<string, string>()
35-
vscode.workspace.workspaceFolders.forEach((folder) => {
36-
workspace_map.set(folder.name, folder.uri.fsPath)
37-
})
38-
const default_workspace = vscode.workspace.workspaceFolders[0].uri.fsPath
38+
const { workspace_map, default_workspace } = get_workspace_map_and_default()
3939

4040
const original_states: OriginalFileState[] = []
4141

4242
for (const file of files) {
43-
let workspace_root = default_workspace
44-
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
45-
workspace_root = workspace_map.get(file.workspace_name)!
46-
} else if (file.workspace_name) {
47-
Logger.warn({
48-
function_name: 'handle_restore_preview',
49-
message: `Workspace '${file.workspace_name}' not found for file '${file.file_path}'. Using default.`
50-
})
51-
}
43+
const workspace_root = resolve_workspace_root({
44+
workspace_name: file.workspace_name,
45+
workspace_map,
46+
default_workspace,
47+
file_path: file.file_path,
48+
function_name: 'handle_restore_preview'
49+
})
5250

5351
const safe_path = create_safe_path(workspace_root, file.file_path)
5452

apps/editor/src/commands/apply-response-command/handlers/search-replace-handler.ts renamed to apps/editor/src/commands/apply-response-command/response-processor/handlers/search-replace-handler.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import * as path from 'path'
44
import { Logger } from '@shared/utils/logger'
55
import { create_safe_path, sanitize_file_name } from '@/utils/path-sanitizer'
66
import { t } from '@/i18n'
7-
import { FileItem } from '../utils/response-parser'
8-
import { OriginalFileState } from '../types/original-file-state'
7+
import { FileItem } from '../../utils/response-parser'
8+
import { OriginalFileState } from '../../types/original-file-state'
9+
import {
10+
get_workspace_map_and_default,
11+
resolve_workspace_root
12+
} from '../../utils/workspace'
913
import {
1014
cleanup_rename_source,
1115
handle_deleted_file_item,
1216
get_rename_source_info
13-
} from '../utils/file-operations'
14-
import { apply_search_replace_to_content } from '../../../utils/changes-integration/search-replace-processor/apply-search-replace-to-content'
15-
import { parse_search_replace_segments } from '../../../utils/changes-integration/search-replace-processor/parse-search-replace-segments'
17+
} from '../../utils/file-operations'
18+
import { apply_search_replace_to_content } from '../../../../utils/changes-integration/search-replace-processor/apply-search-replace-to-content'
19+
import { parse_search_replace_segments } from '../../../../utils/changes-integration/search-replace-processor/parse-search-replace-segments'
1620

1721
export const handle_search_replace = async (params: {
1822
files: FileItem[]
@@ -38,11 +42,7 @@ export const handle_search_replace = async (params: {
3842
return { success: false }
3943
}
4044

41-
const workspace_map = new Map<string, string>()
42-
vscode.workspace.workspaceFolders.forEach((folder) => {
43-
workspace_map.set(folder.name, folder.uri.fsPath)
44-
})
45-
const default_workspace = vscode.workspace.workspaceFolders[0].uri.fsPath
45+
const { workspace_map, default_workspace } = get_workspace_map_and_default()
4646

4747
const original_states: OriginalFileState[] = []
4848
const failed_files: FileItem[] = []
@@ -51,10 +51,11 @@ export const handle_search_replace = async (params: {
5151
for (let i = 0; i < total_files; i++) {
5252
params.on_progress(Math.round((i / total_files) * 100))
5353
const file = params.files[i]
54-
let workspace_root = default_workspace
55-
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
56-
workspace_root = workspace_map.get(file.workspace_name)!
57-
}
54+
const workspace_root = resolve_workspace_root({
55+
workspace_name: file.workspace_name,
56+
workspace_map,
57+
default_workspace
58+
})
5859

5960
const sanitized_path = sanitize_file_name(file.file_path)
6061
const safe_path = create_safe_path(workspace_root, sanitized_path)

apps/editor/src/commands/apply-response-command/handlers/truncated-handler.ts renamed to apps/editor/src/commands/apply-response-command/response-processor/handlers/truncated-handler.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import * as path from 'path'
44
import { Logger } from '@shared/utils/logger'
55
import { create_safe_path, sanitize_file_name } from '@/utils/path-sanitizer'
66
import { t } from '@/i18n'
7-
import { FileItem } from '../utils/response-parser'
8-
import { OriginalFileState } from '../types/original-file-state'
9-
import { process_truncations } from '../../../utils/changes-integration/truncations-processor'
7+
import { FileItem } from '../../utils/response-parser'
8+
import { OriginalFileState } from '../../types/original-file-state'
9+
import {
10+
get_workspace_map_and_default,
11+
resolve_workspace_root
12+
} from '../../utils/workspace'
13+
import { process_truncations } from '../../../../utils/changes-integration/truncations-processor'
1014
import {
1115
cleanup_rename_source,
1216
handle_deleted_file_item,
1317
get_rename_source_info
14-
} from '../utils/file-operations'
18+
} from '../../utils/file-operations'
1519

1620
export const handle_truncated_edit = async (params: {
1721
files: FileItem[]
@@ -37,11 +41,7 @@ export const handle_truncated_edit = async (params: {
3741
return { success: false }
3842
}
3943

40-
const workspace_map = new Map<string, string>()
41-
vscode.workspace.workspaceFolders.forEach((folder) => {
42-
workspace_map.set(folder.name, folder.uri.fsPath)
43-
})
44-
const default_workspace = vscode.workspace.workspaceFolders[0].uri.fsPath
44+
const { workspace_map, default_workspace } = get_workspace_map_and_default()
4545

4646
const original_states: OriginalFileState[] = []
4747
const failed_files: FileItem[] = []
@@ -50,10 +50,11 @@ export const handle_truncated_edit = async (params: {
5050
for (let i = 0; i < total_files; i++) {
5151
params.on_progress(Math.round((i / total_files) * 100))
5252
const file = params.files[i]
53-
let workspace_root = default_workspace
54-
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
55-
workspace_root = workspace_map.get(file.workspace_name)!
56-
}
53+
const workspace_root = resolve_workspace_root({
54+
workspace_name: file.workspace_name,
55+
workspace_map,
56+
default_workspace
57+
})
5758

5859
const sanitized_path = sanitize_file_name(file.file_path)
5960
const safe_path = create_safe_path(workspace_root, sanitized_path)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './response-processor'

0 commit comments

Comments
 (0)