4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
6
import { Codicon } from '../../../../base/common/codicons.js' ;
7
+ import { KeyCode , KeyMod } from '../../../../base/common/keyCodes.js' ;
7
8
import { ResourceSet } from '../../../../base/common/map.js' ;
8
9
import { URI } from '../../../../base/common/uri.js' ;
9
10
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js' ;
10
11
import { localize , localize2 } from '../../../../nls.js' ;
11
12
import { Action2 , MenuId , registerAction2 } from '../../../../platform/actions/common/actions.js' ;
12
13
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js' ;
14
+ import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js' ;
13
15
import { EditorActivation } from '../../../../platform/editor/common/editor.js' ;
16
+ import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js' ;
14
17
import { IListService } from '../../../../platform/list/browser/listService.js' ;
15
18
import { GroupsOrder , IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js' ;
16
19
import { IEditorService } from '../../../services/editor/common/editorService.js' ;
17
20
import { ChatAgentLocation } from '../common/chatAgents.js' ;
18
- import { CONTEXT_CHAT_LOCATION , CONTEXT_CHAT_REQUEST_IN_PROGRESS , CONTEXT_ITEM_ID , CONTEXT_LAST_ITEM_ID , CONTEXT_RESPONSE } from '../common/chatContextKeys.js' ;
21
+ import { CONTEXT_CHAT_LOCATION , CONTEXT_CHAT_REQUEST_IN_PROGRESS , CONTEXT_IN_CHAT_INPUT , CONTEXT_IN_CHAT_SESSION , CONTEXT_REQUEST , CONTEXT_RESPONSE } from '../common/chatContextKeys.js' ;
19
22
import { applyingChatEditsContextKey , CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME , chatEditingResourceContextKey , chatEditingWidgetFileStateContextKey , decidedChatEditingResourceContextKey , IChatEditingService , IChatEditingSession , inChatEditingSessionContextKey , isChatRequestCheckpointed , WorkingSetEntryState } from '../common/chatEditingService.js' ;
20
- import { isResponseVM } from '../common/chatViewModel.js' ;
23
+ import { IChatService } from '../common/chatService.js' ;
24
+ import { isRequestVM , isResponseVM } from '../common/chatViewModel.js' ;
21
25
import { CHAT_CATEGORY } from './actions/chatActions.js' ;
22
- import { IChatWidget , IChatWidgetService } from './chat.js' ;
26
+ import { ChatTreeItem , IChatWidget , IChatWidgetService } from './chat.js' ;
23
27
24
28
abstract class WorkingSetAction extends Action2 {
25
29
run ( accessor : ServicesAccessor , ...args : any [ ] ) {
@@ -295,11 +299,8 @@ registerAction2(class RestoreWorkingSetAction extends Action2 {
295
299
id : MenuId . ChatMessageFooter ,
296
300
group : 'navigation' ,
297
301
order : 1000 ,
298
- when : ContextKeyExpr . and (
299
- CONTEXT_CHAT_LOCATION . isEqualTo ( ChatAgentLocation . EditingSession ) ,
300
- CONTEXT_RESPONSE ,
301
- ContextKeyExpr . notIn ( CONTEXT_ITEM_ID . key , CONTEXT_LAST_ITEM_ID . key )
302
- )
302
+ when : ContextKeyExpr . false ( )
303
+ // when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession), CONTEXT_RESPONSE, ContextKeyExpr.notIn(CONTEXT_ITEM_ID.key, CONTEXT_LAST_ITEM_ID.key)
303
304
}
304
305
} ) ;
305
306
}
@@ -312,13 +313,110 @@ registerAction2(class RestoreWorkingSetAction extends Action2 {
312
313
}
313
314
314
315
const { session, requestId } = item . model ;
315
- if ( requestId === session . checkpoint ?. id ) {
316
+ const shouldUnsetCheckpoint = requestId === session . checkpoint ?. id ;
317
+ if ( shouldUnsetCheckpoint ) {
316
318
// Unset the existing checkpoint
317
319
session . setCheckpoint ( undefined ) ;
318
320
} else {
319
321
session . setCheckpoint ( requestId ) ;
320
322
}
321
323
322
- chatEditingService . restoreSnapshot ( requestId ) ;
324
+ // The next request is associated with the working set snapshot representing
325
+ // the 'good state' from this checkpointed request
326
+ const chatService = accessor . get ( IChatService ) ;
327
+ const chatModel = chatService . getSession ( item . sessionId ) ;
328
+ const chatRequests = chatModel ?. getRequests ( ) ;
329
+ const snapshot = chatRequests ?. find ( ( v , i ) => i > 0 && chatRequests [ i - 1 ] ?. id === requestId ) ;
330
+ if ( ! shouldUnsetCheckpoint && snapshot !== undefined ) {
331
+ chatEditingService . restoreSnapshot ( snapshot . id ) ;
332
+ } else if ( shouldUnsetCheckpoint ) {
333
+ chatEditingService . restoreSnapshot ( undefined ) ;
334
+ }
335
+ }
336
+ } ) ;
337
+
338
+ registerAction2 ( class RemoveAction extends Action2 {
339
+ constructor ( ) {
340
+ super ( {
341
+ id : 'workbench.action.chat.undoEdits' ,
342
+ title : localize2 ( 'chat.undoEdits.label' , "Undo Edits" ) ,
343
+ f1 : false ,
344
+ category : CHAT_CATEGORY ,
345
+ icon : Codicon . trashcan ,
346
+ keybinding : {
347
+ primary : KeyCode . Delete ,
348
+ mac : {
349
+ primary : KeyMod . CtrlCmd | KeyCode . Backspace ,
350
+ } ,
351
+ when : ContextKeyExpr . and ( CONTEXT_CHAT_LOCATION . isEqualTo ( ChatAgentLocation . EditingSession ) , CONTEXT_IN_CHAT_SESSION , CONTEXT_IN_CHAT_INPUT . negate ( ) ) ,
352
+ weight : KeybindingWeight . WorkbenchContrib ,
353
+ } ,
354
+ menu : [
355
+ {
356
+ id : MenuId . ChatMessageFooter ,
357
+ group : 'navigation' ,
358
+ order : 4 ,
359
+ when : ContextKeyExpr . and ( CONTEXT_CHAT_LOCATION . isEqualTo ( ChatAgentLocation . EditingSession ) , CONTEXT_RESPONSE )
360
+ } ,
361
+ {
362
+ id : MenuId . ChatMessageTitle ,
363
+ group : 'navigation' ,
364
+ order : 2 ,
365
+ when : ContextKeyExpr . and ( CONTEXT_CHAT_LOCATION . isEqualTo ( ChatAgentLocation . EditingSession ) , CONTEXT_REQUEST )
366
+ }
367
+ ]
368
+ } ) ;
369
+ }
370
+
371
+ async run ( accessor : ServicesAccessor , ...args : any [ ] ) {
372
+ let item : ChatTreeItem | undefined = args [ 0 ] ;
373
+ if ( ! isResponseVM ( item ) ) {
374
+ const chatWidgetService = accessor . get ( IChatWidgetService ) ;
375
+ const widget = chatWidgetService . lastFocusedWidget ;
376
+ item = widget ?. getFocus ( ) ;
377
+ }
378
+
379
+ if ( ! item ) {
380
+ return ;
381
+ }
382
+
383
+ const chatService = accessor . get ( IChatService ) ;
384
+ const chatModel = chatService . getSession ( item . sessionId ) ;
385
+ if ( chatModel ?. initialLocation !== ChatAgentLocation . EditingSession ) {
386
+ return ;
387
+ }
388
+
389
+ const requestId = isRequestVM ( item ) ? item . id :
390
+ isResponseVM ( item ) ? item . requestId : undefined ;
391
+
392
+ if ( requestId ) {
393
+ const dialogService = accessor . get ( IDialogService ) ;
394
+ const chatEditingService = accessor . get ( IChatEditingService ) ;
395
+ const chatRequests = chatModel . getRequests ( ) ;
396
+ const itemIndex = chatRequests . findIndex ( request => request . id === requestId ) ;
397
+ const editsToUndo = chatRequests . length - itemIndex ;
398
+
399
+ const confirmation = await dialogService . confirm ( {
400
+ title : editsToUndo === 1
401
+ ? localize ( 'chat.removeLast.confirmation.title' , "Do you want to undo your last edit?" )
402
+ : localize ( 'chat.remove.confirmation.title' , "Do you want to undo {0} edits?" , editsToUndo ) ,
403
+ message : editsToUndo === 1
404
+ ? localize ( 'chat.removeLast.confirmation.message' , "This will remove your last request and undo the edits it made to your working set." )
405
+ : localize ( 'chat.remove.confirmation.message' , "This will remove all subsequent requests and undo the edits they made to your working set." ) ,
406
+ primaryButton : localize ( 'chat.remove.confirmation.primaryButton' , "Yes" ) ,
407
+ type : 'info'
408
+ } ) ;
409
+
410
+ if ( confirmation . confirmed ) {
411
+ // Restore the snapshot to what it was before the request(s) that we deleted
412
+ const snapshotRequestId = chatRequests [ itemIndex ] . id ;
413
+ await chatEditingService . restoreSnapshot ( snapshotRequestId ) ;
414
+
415
+ // Remove the request and all that come after it
416
+ for ( const request of chatRequests . slice ( itemIndex ) ) {
417
+ await chatService . removeRequest ( item . sessionId , request . id ) ;
418
+ }
419
+ }
420
+ }
323
421
}
324
422
} ) ;
0 commit comments