Skip to content

Commit 007cd58

Browse files
committed
Refactor the applyChatResponse command by extracting complex response processing, configuration retrieval, file checking, and review cleanup logic into dedicated utility modules to improve maintainability and separation of concerns
1 parent 9bb847d commit 007cd58

16 files changed

Lines changed: 1498 additions & 1407 deletions

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

Lines changed: 19 additions & 905 deletions
Large diffs are not rendered by default.

‎packages/vscode/src/commands/apply-chat-response-command/response-processor.ts‎

Lines changed: 554 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import * as vscode from 'vscode'
2+
import {
3+
ModelProvidersManager,
4+
get_tool_config_id
5+
} from '@/services/model-providers-manager'
6+
import { LAST_SELECTED_INTELLIGENT_UPDATE_CONFIG_ID_STATE_KEY } from '@/constants/state-keys'
7+
import { dictionary } from '@shared/constants/dictionary'
8+
import { Logger } from '@shared/utils/logger'
9+
10+
export const get_intelligent_update_config = async (
11+
api_providers_manager: ModelProvidersManager,
12+
show_quick_pick: boolean = false,
13+
context: vscode.ExtensionContext
14+
): Promise<{ provider: any; config: any } | undefined> => {
15+
const intelligent_update_configs =
16+
await api_providers_manager.get_intelligent_update_tool_configs()
17+
18+
if (intelligent_update_configs.length == 0) {
19+
vscode.commands.executeCommand('codeWebChat.settings')
20+
vscode.window.showInformationMessage(
21+
dictionary.information_message.NO_INTELLIGENT_UPDATE_CONFIGURATIONS_FOUND
22+
)
23+
return
24+
}
25+
26+
let selected_config = null
27+
28+
if (!show_quick_pick) {
29+
selected_config =
30+
await api_providers_manager.get_default_intelligent_update_config()
31+
}
32+
33+
if (!selected_config || show_quick_pick) {
34+
const set_default_button = {
35+
iconPath: new vscode.ThemeIcon('star'),
36+
tooltip: 'Set as default'
37+
}
38+
39+
const unset_default_button = {
40+
iconPath: new vscode.ThemeIcon('star-full'),
41+
tooltip: 'Unset default'
42+
}
43+
44+
const create_items = async () => {
45+
const default_config =
46+
await api_providers_manager.get_default_intelligent_update_config()
47+
48+
return intelligent_update_configs.map((config, index) => {
49+
const buttons = []
50+
51+
const is_default =
52+
default_config &&
53+
default_config.provider_type == config.provider_type &&
54+
default_config.provider_name == config.provider_name &&
55+
default_config.model == config.model
56+
57+
if (is_default) {
58+
buttons.push(unset_default_button)
59+
} else {
60+
buttons.push(set_default_button)
61+
}
62+
63+
return {
64+
label: config.model,
65+
description: `${
66+
config.reasoning_effort ? `${config.reasoning_effort}` : ''
67+
}${
68+
config.reasoning_effort
69+
? ` · ${config.provider_name}`
70+
: `${config.provider_name}`
71+
}`,
72+
config,
73+
index,
74+
id: get_tool_config_id(config),
75+
buttons
76+
}
77+
})
78+
}
79+
80+
const quick_pick = vscode.window.createQuickPick()
81+
const items = await create_items()
82+
quick_pick.items = items
83+
quick_pick.placeholder = 'Select intelligent update configuration'
84+
quick_pick.matchOnDescription = true
85+
86+
const last_selected_id =
87+
context.workspaceState.get<string>(
88+
LAST_SELECTED_INTELLIGENT_UPDATE_CONFIG_ID_STATE_KEY
89+
) ??
90+
context.globalState.get<string>(
91+
LAST_SELECTED_INTELLIGENT_UPDATE_CONFIG_ID_STATE_KEY
92+
)
93+
const last_selected_item = items.find((item) => item.id == last_selected_id)
94+
95+
if (last_selected_item) {
96+
quick_pick.activeItems = [last_selected_item]
97+
} else if (items.length > 0) {
98+
quick_pick.activeItems = [items[0]]
99+
}
100+
101+
return new Promise<{ provider: any; config: any } | undefined>(
102+
(resolve) => {
103+
quick_pick.onDidTriggerItemButton(async (event) => {
104+
const item = event.item as any
105+
const button = event.button
106+
const index = item.index
107+
108+
if (button === set_default_button) {
109+
await api_providers_manager.set_default_intelligent_update_config(
110+
intelligent_update_configs[index]
111+
)
112+
quick_pick.items = await create_items()
113+
} else if (button === unset_default_button) {
114+
await api_providers_manager.set_default_intelligent_update_config(
115+
null as any
116+
)
117+
quick_pick.items = await create_items()
118+
}
119+
})
120+
121+
quick_pick.onDidAccept(async () => {
122+
const selected = quick_pick.selectedItems[0] as any
123+
quick_pick.hide()
124+
125+
if (!selected) {
126+
resolve(undefined)
127+
return
128+
}
129+
130+
context.workspaceState.update(
131+
LAST_SELECTED_INTELLIGENT_UPDATE_CONFIG_ID_STATE_KEY,
132+
selected.id
133+
)
134+
context.globalState.update(
135+
LAST_SELECTED_INTELLIGENT_UPDATE_CONFIG_ID_STATE_KEY,
136+
selected.id
137+
)
138+
139+
const provider = await api_providers_manager.get_provider(
140+
selected.config.provider_name
141+
)
142+
if (!provider) {
143+
vscode.window.showErrorMessage(
144+
dictionary.error_message.API_PROVIDER_FOR_CONFIG_NOT_FOUND
145+
)
146+
resolve(undefined)
147+
return
148+
}
149+
150+
resolve({
151+
provider,
152+
config: selected.config
153+
})
154+
})
155+
156+
quick_pick.onDidHide(() => {
157+
quick_pick.dispose()
158+
resolve(undefined)
159+
})
160+
161+
quick_pick.show()
162+
}
163+
)
164+
}
165+
166+
const provider = await api_providers_manager.get_provider(
167+
selected_config.provider_name
168+
)
169+
170+
if (!provider) {
171+
vscode.window.showErrorMessage(
172+
dictionary.error_message.API_PROVIDER_NOT_FOUND
173+
)
174+
Logger.warn({
175+
function_name: 'get_intelligent_update_config',
176+
message: 'API provider not found for Intelligent Update API tool.'
177+
})
178+
return
179+
}
180+
181+
return {
182+
provider,
183+
config: selected_config
184+
}
185+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as vscode from 'vscode'
2+
import * as fs from 'fs'
3+
import { ClipboardFile } from './clipboard-parser'
4+
import { create_safe_path } from '@/utils/path-sanitizer'
5+
6+
export const check_if_all_files_new = async (
7+
files: ClipboardFile[]
8+
): Promise<boolean> => {
9+
const workspace_map = new Map<string, string>()
10+
vscode.workspace.workspaceFolders!.forEach((folder) => {
11+
workspace_map.set(folder.name, folder.uri.fsPath)
12+
})
13+
const default_workspace = vscode.workspace.workspaceFolders![0].uri.fsPath
14+
15+
for (const file of files) {
16+
let workspace_root = default_workspace
17+
if (file.workspace_name && workspace_map.has(file.workspace_name)) {
18+
workspace_root = workspace_map.get(file.workspace_name)!
19+
}
20+
21+
const safe_path = create_safe_path(workspace_root, file.file_path)
22+
23+
if (safe_path && fs.existsSync(safe_path)) {
24+
return false
25+
}
26+
}
27+
28+
return true
29+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import * as vscode from 'vscode'
2+
import { Logger } from '@shared/utils/logger'
3+
import { OriginalFileState } from '../types/original-file-state'
4+
import { undo_files } from './file-operations'
5+
import { review } from './review/review'
6+
import { PanelProvider } from '@/views/panel/backend/panel-provider'
7+
import { update_undo_button_state } from './state-manager'
8+
9+
export let ongoing_review_cleanup_promise: Promise<void> | null = null
10+
11+
export const handle_code_review_and_cleanup = async (params: {
12+
original_states: OriginalFileState[]
13+
chat_response: string
14+
panel_provider: PanelProvider
15+
context: vscode.ExtensionContext
16+
original_editor_state?: {
17+
file_path: string
18+
position: { line: number; character: number }
19+
}
20+
raw_instructions?: string
21+
}): Promise<boolean> => {
22+
let resolve_cleanup_promise: () => void
23+
ongoing_review_cleanup_promise = new Promise((resolve) => {
24+
resolve_cleanup_promise = resolve
25+
})
26+
27+
try {
28+
const review_result = await review({
29+
original_states: params.original_states,
30+
panel_provider: params.panel_provider,
31+
raw_instructions: params.raw_instructions
32+
})
33+
34+
if (review_result === null || review_result.accepted_files.length == 0) {
35+
if (params.original_editor_state) {
36+
try {
37+
const uri = vscode.Uri.file(params.original_editor_state.file_path)
38+
const document = await vscode.workspace.openTextDocument(uri)
39+
const editor = await vscode.window.showTextDocument(document, {
40+
preview: false
41+
})
42+
const position = new vscode.Position(
43+
params.original_editor_state.position.line,
44+
params.original_editor_state.position.character
45+
)
46+
editor.selection = new vscode.Selection(position, position)
47+
editor.revealRange(
48+
new vscode.Range(position, position),
49+
vscode.TextEditorRevealType.InCenter
50+
)
51+
} catch (error) {
52+
Logger.error({
53+
function_name: 'handle_code_review_and_cleanup',
54+
message: 'Error restoring original editor state',
55+
data: error
56+
})
57+
}
58+
}
59+
await undo_files({
60+
original_states: params.original_states
61+
})
62+
update_undo_button_state({
63+
context: params.context,
64+
panel_provider: params.panel_provider,
65+
states: null
66+
})
67+
return false
68+
}
69+
70+
if (review_result.rejected_states.length > 0) {
71+
await undo_files({
72+
original_states: review_result.rejected_states
73+
})
74+
}
75+
76+
const accepted_states = params.original_states.filter((state) =>
77+
review_result.accepted_files.some(
78+
(accepted) =>
79+
accepted.file_path == state.file_path &&
80+
accepted.workspace_name == state.workspace_name
81+
)
82+
)
83+
84+
if (accepted_states.length > 0) {
85+
update_undo_button_state({
86+
context: params.context,
87+
panel_provider: params.panel_provider,
88+
states: accepted_states,
89+
applied_content: params.chat_response,
90+
original_editor_state: params.original_editor_state
91+
})
92+
93+
return true
94+
} else {
95+
update_undo_button_state({
96+
context: params.context,
97+
panel_provider: params.panel_provider,
98+
states: null
99+
})
100+
return false
101+
}
102+
} finally {
103+
resolve_cleanup_promise!()
104+
ongoing_review_cleanup_promise = null
105+
}
106+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { createTwoFilesPatch } from 'diff'
2+
3+
export const get_diff_stats = (params: {
4+
original_content: string
5+
new_content: string
6+
}): { lines_added: number; lines_removed: number } => {
7+
const original_content_processed = params.original_content
8+
.split(/\r?\n/)
9+
.map((line) => line.trim())
10+
.join('\n')
11+
const new_content_processed = params.new_content
12+
.split(/\r?\n/)
13+
.map((line) => line.trim())
14+
.join('\n')
15+
if (original_content_processed === new_content_processed) {
16+
return { lines_added: 0, lines_removed: 0 }
17+
}
18+
19+
const patch = createTwoFilesPatch(
20+
'original',
21+
'modified',
22+
original_content_processed,
23+
new_content_processed,
24+
undefined,
25+
undefined,
26+
{ context: 0 }
27+
)
28+
29+
let lines_added = 0
30+
let lines_removed = 0
31+
32+
const lines = patch.split('\n')
33+
for (const line of lines) {
34+
if (line.startsWith('+') && !line.startsWith('+++')) {
35+
lines_added++
36+
} else if (line.startsWith('-') && !line.startsWith('---')) {
37+
lines_removed++
38+
}
39+
}
40+
41+
return { lines_added, lines_removed }
42+
}

0 commit comments

Comments
 (0)