@@ -7,6 +7,11 @@ import {
77 process_file
88} from '../utils/intelligent-update-utils'
99import { dictionary } from '@shared/constants/dictionary'
10+ import {
11+ LAST_REFACTOR_INSTRUCTION_SOURCE_STATE_KEY ,
12+ LAST_REFACTOR_INSTRUCTION_STATE_KEY
13+ } from '../constants/state-keys'
14+ import { Logger } from '@shared/utils/logger'
1015
1116export const refactor_current_file_command = (
1217 context : vscode . ExtensionContext
@@ -24,25 +29,82 @@ export const refactor_current_file_command = (
2429
2530 let instruction : string | undefined
2631 const clipboard_content = await vscode . env . clipboard . readText ( )
32+
33+ const last_instruction_source = context . workspaceState . get < string > (
34+ LAST_REFACTOR_INSTRUCTION_SOURCE_STATE_KEY
35+ )
36+ const last_instruction = context . workspaceState . get < string > (
37+ LAST_REFACTOR_INSTRUCTION_STATE_KEY
38+ )
39+
2740 if ( ! clipboard_content ) {
2841 instruction = await vscode . window . showInputBox ( {
29- prompt : 'Enter your refactoring instructions'
42+ prompt : 'Enter your refactoring instructions' ,
43+ value : last_instruction
3044 } )
45+ if ( instruction ) {
46+ await context . workspaceState . update (
47+ LAST_REFACTOR_INSTRUCTION_STATE_KEY ,
48+ instruction
49+ )
50+ await context . workspaceState . update (
51+ LAST_REFACTOR_INSTRUCTION_SOURCE_STATE_KEY ,
52+ 'Instructions'
53+ )
54+ }
3155 } else {
32- const choice = await vscode . window . showQuickPick (
33- [ 'Clipboard' , 'Instructions' ] ,
34- {
35- placeHolder :
36- 'Use clipboard content or enter new refactoring instructions?'
56+ const choice = await new Promise < string | undefined > ( ( resolve ) => {
57+ const quick_pick = vscode . window . createQuickPick ( )
58+ const items = [ { label : 'Clipboard' } , { label : 'Instructions' } ]
59+ quick_pick . items = items
60+ quick_pick . placeholder =
61+ 'Use clipboard content or enter new refactoring instructions?'
62+
63+ if ( last_instruction_source ) {
64+ const active_item = items . find (
65+ ( item ) => item . label === last_instruction_source
66+ )
67+ if ( active_item ) {
68+ quick_pick . activeItems = [ active_item ]
69+ }
3770 }
71+
72+ quick_pick . onDidAccept ( ( ) => {
73+ const selected = quick_pick . selectedItems [ 0 ]
74+ resolve ( selected ?. label )
75+ quick_pick . hide ( )
76+ } )
77+
78+ quick_pick . onDidHide ( ( ) => {
79+ quick_pick . dispose ( )
80+ resolve ( undefined )
81+ } )
82+
83+ quick_pick . show ( )
84+ } )
85+
86+ if ( choice === undefined ) {
87+ return // User cancelled
88+ }
89+
90+ await context . workspaceState . update (
91+ LAST_REFACTOR_INSTRUCTION_SOURCE_STATE_KEY ,
92+ choice
3893 )
3994
4095 if ( choice == 'Clipboard' ) {
4196 instruction = clipboard_content
4297 } else if ( choice == 'Instructions' ) {
4398 instruction = await vscode . window . showInputBox ( {
44- prompt : 'Enter your refactoring instructions'
99+ prompt : 'Enter your refactoring instructions' ,
100+ value : last_instruction
45101 } )
102+ if ( instruction ) {
103+ await context . workspaceState . update (
104+ LAST_REFACTOR_INSTRUCTION_STATE_KEY ,
105+ instruction
106+ )
107+ }
46108 }
47109 }
48110
@@ -74,89 +136,161 @@ export const refactor_current_file_command = (
74136 const document = editor . document
75137 const original_content = document . getText ( )
76138 const file_path = document . uri . fsPath
139+ const cancel_token_source = axios . CancelToken . source ( )
140+
141+ let thinking_reported = false
142+ let resolve_thinking : ( ) => void
143+ const thinking_promise = new Promise < void > ( ( resolve ) => {
144+ resolve_thinking = resolve
145+ } )
146+
147+ const on_thinking_chunk = ( ) => {
148+ if ( ! thinking_reported ) {
149+ thinking_reported = true
150+ resolve_thinking ( )
151+ }
152+ }
153+
154+ let receiving_reported = false
155+ let resolve_receiving : ( ) => void
156+ const receiving_promise = new Promise < void > ( ( resolve ) => {
157+ resolve_receiving = resolve
158+ } )
159+
160+ const on_chunk = ( ) => {
161+ if ( ! receiving_reported ) {
162+ receiving_reported = true
163+ resolve_receiving ( )
164+ }
165+ }
166+
167+ const content_promise = process_file ( {
168+ endpoint_url,
169+ api_key : provider . api_key ,
170+ provider,
171+ model : intelligent_update_config . model ,
172+ temperature : intelligent_update_config . temperature ,
173+ reasoning_effort : intelligent_update_config . reasoning_effort ,
174+ file_path : file_path ,
175+ file_content : original_content ,
176+ instruction,
177+ cancel_token : cancel_token_source . token ,
178+ on_thinking_chunk,
179+ on_chunk
180+ } )
77181
78- let result : any
79182 try {
80- result = await vscode . window . withProgress (
183+ await vscode . window . withProgress (
81184 {
82185 location : vscode . ProgressLocation . Notification ,
83- title : `Refactoring current file` ,
186+ title : dictionary . api_call . WAITING_FOR_API_RESPONSE ,
84187 cancellable : true
85188 } ,
86189 async ( progress , token ) => {
87- const cancel_token_source = axios . CancelToken . source ( )
88190 token . onCancellationRequested ( ( ) => {
89- cancel_token_source . cancel ( 'Cancelled by user. ' )
191+ cancel_token_source . cancel ( 'User cancelled the operation ' )
90192 } )
91193
92- let previous_progress = 0
93- const estimated_total_tokens = Math . ceil (
94- original_content . length / 4
95- )
194+ let wait_time = 0
195+ const wait_timer = setInterval ( ( ) => {
196+ progress . report ( {
197+ message : `${ ( wait_time / 10 ) . toFixed ( 1 ) } s`
198+ } )
199+ wait_time ++
200+ } , 100 )
201+
202+ await Promise . race ( [
203+ content_promise ,
204+ thinking_promise ,
205+ receiving_promise
206+ ] )
207+ clearInterval ( wait_timer )
208+ }
209+ )
96210
97- const content = await process_file ( {
98- endpoint_url,
99- api_key : provider . api_key ,
100- model : intelligent_update_config . model ,
101- temperature : intelligent_update_config . temperature ,
102- reasoning_effort : intelligent_update_config . reasoning_effort ,
103- file_path : file_path ,
104- file_content : original_content ,
105- instruction,
106- cancel_token : cancel_token_source . token ,
107- on_chunk : ( tokens_per_second , total_tokens ) => {
108- if ( estimated_total_tokens > 0 ) {
109- const current_progress = Math . min (
110- Math . round ( ( total_tokens / estimated_total_tokens ) * 100 ) ,
111- 100
112- )
113- const increment = current_progress - previous_progress
114- if ( increment > 0 ) {
115- progress . report ( {
116- increment,
117- message : `~${ tokens_per_second } tokens/s`
118- } )
119- previous_progress = current_progress
120- }
121- }
211+ if ( thinking_reported && ! receiving_reported ) {
212+ await vscode . window . withProgress (
213+ {
214+ location : vscode . ProgressLocation . Notification ,
215+ title : dictionary . api_call . THINKING ,
216+ cancellable : true
217+ } ,
218+ async ( progress , token ) => {
219+ token . onCancellationRequested ( ( ) => {
220+ cancel_token_source . cancel ( 'User cancelled the operation' )
221+ } )
222+
223+ let thinking_time = 0
224+ const thinking_timer = setInterval ( ( ) => {
225+ progress . report ( {
226+ message : `${ ( thinking_time / 10 ) . toFixed ( 1 ) } s`
227+ } )
228+ thinking_time ++
229+ } , 100 )
230+
231+ try {
232+ await Promise . race ( [ content_promise , receiving_promise ] )
233+ } finally {
234+ clearInterval ( thinking_timer )
122235 }
123- } )
236+ }
237+ )
238+ }
239+
240+ if ( receiving_reported ) {
241+ await vscode . window . withProgress (
242+ {
243+ location : vscode . ProgressLocation . Notification ,
244+ title : dictionary . api_call . RECEIVING_RESPONSE ,
245+ cancellable : true
246+ } ,
247+ async ( progress , token ) => {
248+ token . onCancellationRequested ( ( ) => {
249+ cancel_token_source . cancel ( 'User cancelled the operation' )
250+ } )
124251
125- return {
126- content,
127- cancelled : token . isCancellationRequested
252+ let receiving_time = 0
253+ const receiving_timer = setInterval ( ( ) => {
254+ progress . report ( {
255+ message : `${ ( receiving_time / 10 ) . toFixed ( 1 ) } s`
256+ } )
257+ receiving_time ++
258+ } , 100 )
259+
260+ try {
261+ await content_promise
262+ } finally {
263+ clearInterval ( receiving_timer )
264+ }
128265 }
129- }
130- )
131- } catch ( error ) {
132- if ( axios . isCancel ( error ) ) {
133- return
266+ )
134267 }
135- throw error
136- }
137268
138- if ( result . cancelled ) {
139- return
140- }
269+ const updated_content = await content_promise
141270
142- const updated_content = result . content
271+ if ( updated_content ) {
272+ const relative_path = vscode . workspace . asRelativePath ( document . uri )
273+ const response_for_apply = `\`\`\`\n// ${ relative_path } \n${ updated_content } \n\`\`\``
143274
144- if ( updated_content ) {
145- const relative_path = vscode . workspace . asRelativePath ( document . uri )
146- const response_for_apply = `\`\`\`\n// ${ relative_path } \n${ updated_content } \n\`\`\``
275+ await vscode . commands . executeCommand (
276+ 'codeWebChat.applyChatResponse' ,
277+ {
278+ response : response_for_apply ,
279+ suppress_fast_replace_inaccuracies_dialog : true
280+ }
281+ )
147282
148- await vscode . commands . executeCommand ( 'codeWebChat.applyChatResponse' , {
149- response : response_for_apply ,
150- suppress_fast_replace_inaccuracies_dialog : true
283+ await vscode . window . showInformationMessage (
284+ dictionary . information_message
285+ . CLIPBOARD_CONTENT_APPLIED_SUCCESSFULLY
286+ )
287+ }
288+ } catch ( err : any ) {
289+ Logger . error ( {
290+ function_name : 'refactorCurrentFile' ,
291+ message : 'Refactor error' ,
292+ data : err
151293 } )
152-
153- await vscode . window . showInformationMessage (
154- dictionary . information_message . CLIPBOARD_CONTENT_APPLIED_SUCCESSFULLY
155- )
156- } else {
157- vscode . window . showErrorMessage (
158- dictionary . error_message . FAILED_TO_APPLY_CLIPBOARD_CONTENT
159- )
160294 }
161295 }
162296 )
0 commit comments