@@ -14,7 +14,7 @@ import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
1414import { IDiffProviderFactoryService } from 'vs/editor/browser/widget/diffEditor/diffProviderFactoryService' ;
1515import { EditOperation } from 'vs/editor/common/core/editOperation' ;
1616import { Range } from 'vs/editor/common/core/range' ;
17- import { ITextModel } from 'vs/editor/common/model' ;
17+ import { EndOfLineSequence , ITextModel } from 'vs/editor/common/model' ;
1818import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker' ;
1919import { IModelService } from 'vs/editor/common/services/model' ;
2020import { TestDiffProviderFactoryService } from 'vs/editor/test/browser/diff/testDiffProviderFactoryService' ;
@@ -27,16 +27,16 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
2727import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock' ;
2828import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService' ;
2929import { IEditorProgressService , IProgressRunner } from 'vs/platform/progress/common/progress' ;
30- import { IViewDescriptorService } from 'vs/workbench/common/views' ;
30+ import { IView , IViewDescriptorService } from 'vs/workbench/common/views' ;
3131import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration' ;
3232import { IAccessibleViewService } from 'vs/platform/accessibility/browser/accessibleView' ;
33- import { IChatAccessibilityService , IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat' ;
33+ import { IChatAccessibilityService , IChatWidget , IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat' ;
3434import { ChatAgentLocation , ChatAgentService , IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' ;
3535import { IChatResponseViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel' ;
3636import { InlineChatController , InlineChatRunOptions , State } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController' ;
3737import { Session } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession' ;
3838import { CTX_INLINE_CHAT_USER_DID_EDIT , EditMode , InlineChatConfigKeys } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
39- import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices' ;
39+ import { TestViewsService , workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices' ;
4040import { IInlineChatSavingService } from '../../browser/inlineChatSavingService' ;
4141import { IInlineChatSessionService } from '../../browser/inlineChatSessionService' ;
4242import { InlineChatSessionServiceImpl } from '../../browser/inlineChatSessionServiceImpl' ;
@@ -61,6 +61,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
6161import { TestCommandService } from 'vs/editor/test/browser/editorTestServices' ;
6262import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService' ;
6363import { RerunAction } from 'vs/workbench/contrib/inlineChat/browser/inlineChatActions' ;
64+ import { CancellationToken } from 'vs/base/common/cancellation' ;
6465
6566suite ( 'InteractiveChatController' , function ( ) {
6667
@@ -127,10 +128,13 @@ suite('InteractiveChatController', function () {
127128 let model : ITextModel ;
128129 let ctrl : TestController ;
129130 let contextKeyService : MockContextKeyService ;
131+ let chatService : IChatService ;
130132 let chatAgentService : IChatAgentService ;
131133 let inlineChatSessionService : IInlineChatSessionService ;
132134 let instaService : TestInstantiationService ;
133135
136+ let chatWidget : IChatWidget ;
137+
134138 setup ( function ( ) {
135139
136140 const serviceCollection = new ServiceCollection (
@@ -141,7 +145,11 @@ suite('InteractiveChatController', function () {
141145 [ IHoverService , NullHoverService ] ,
142146 [ IExtensionService , new TestExtensionService ( ) ] ,
143147 [ IContextKeyService , new MockContextKeyService ( ) ] ,
144- [ IViewsService , new TestExtensionService ( ) ] ,
148+ [ IViewsService , new class extends TestViewsService {
149+ override async openView < T extends IView > ( id : string , focus ?: boolean | undefined ) : Promise < T | null > {
150+ return { widget : chatWidget ?? null } as any ;
151+ }
152+ } ( ) ] ,
145153 [ IWorkspaceContextService , new TestContextService ( ) ] ,
146154 [ IChatWidgetHistoryService , new SyncDescriptor ( ChatWidgetHistoryService ) ] ,
147155 [ IChatWidgetService , new SyncDescriptor ( ChatWidgetService ) ] ,
@@ -193,12 +201,13 @@ suite('InteractiveChatController', function () {
193201 configurationService . setUserConfiguration ( 'editor' , { } ) ;
194202
195203 contextKeyService = instaService . get ( IContextKeyService ) as MockContextKeyService ;
196-
204+ chatService = instaService . get ( IChatService ) ;
197205 chatAgentService = instaService . get ( IChatAgentService ) ;
198206
199207 inlineChatSessionService = store . add ( instaService . get ( IInlineChatSessionService ) ) ;
200208
201209 model = store . add ( instaService . get ( IModelService ) . createModel ( 'Hello\nWorld\nHello Again\nHello World\n' , null ) ) ;
210+ model . setEOL ( EndOfLineSequence . LF ) ;
202211 editor = store . add ( instantiateTestCodeEditor ( instaService , model ) ) ;
203212
204213 store . add ( chatAgentService . registerDynamicAgent ( { id : 'testEditorAgent' , ...agentData , } , {
@@ -494,4 +503,143 @@ suite('InteractiveChatController', function () {
494503 ctrl . finishExistingSession ( ) ;
495504 await r ;
496505 } ) ;
506+
507+ test ( 'Retry undoes all changes, not just those from the request#5736' , async function ( ) {
508+
509+ const text = [
510+ 'eins-' ,
511+ 'zwei-' ,
512+ 'drei-'
513+ ] ;
514+
515+ store . add ( chatAgentService . registerDynamicAgent ( {
516+ id : 'testEditorAgent2' ,
517+ ...agentData
518+ } , {
519+ async invoke ( request , progress , history , token ) {
520+ progress ( { kind : 'textEdit' , uri : model . uri , edits : [ { range : new Range ( 1 , 1 , 1 , 1 ) , text : text . shift ( ) ?? '' } ] } ) ;
521+ return { } ;
522+ } ,
523+ } ) ) ;
524+
525+ ctrl = instaService . createInstance ( TestController , editor ) ;
526+ const rerun = new RerunAction ( ) ;
527+
528+ model . setValue ( '' ) ;
529+
530+ // REQUEST 1
531+ const p = ctrl . waitFor ( [ ...TestController . INIT_SEQUENCE , State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
532+ const r = ctrl . run ( { message : '1' , autoSend : true } ) ;
533+ await p ;
534+
535+ assert . strictEqual ( model . getValue ( ) , 'eins-' ) ;
536+
537+ // REQUEST 2
538+ const p2 = ctrl . waitFor ( [ State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
539+ await ctrl . acceptInput ( ) ;
540+ await p2 ;
541+
542+ assert . strictEqual ( model . getValue ( ) , 'zwei-eins-' ) ;
543+
544+ // REQUEST 2 - RERUN
545+ const p3 = ctrl . waitFor ( [ State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
546+ await instaService . invokeFunction ( rerun . runInlineChatCommand , ctrl , editor ) ;
547+ await p3 ;
548+
549+ assert . strictEqual ( model . getValue ( ) , 'drei-eins-' ) ;
550+
551+ ctrl . finishExistingSession ( ) ;
552+ await r ;
553+
554+ } ) ;
555+
556+ test ( 'moving inline chat to another model undoes changes' , async function ( ) {
557+ const text = [
558+ 'eins\n' ,
559+ 'zwei\n'
560+ ] ;
561+
562+ store . add ( chatAgentService . registerDynamicAgent ( {
563+ id : 'testEditorAgent2' ,
564+ ...agentData
565+ } , {
566+ async invoke ( request , progress , history , token ) {
567+ progress ( { kind : 'textEdit' , uri : model . uri , edits : [ { range : new Range ( 1 , 1 , 1 , 1 ) , text : text . shift ( ) ?? '' } ] } ) ;
568+ return { } ;
569+ } ,
570+ } ) ) ;
571+ ctrl = instaService . createInstance ( TestController , editor ) ;
572+
573+ // REQUEST 1
574+ const p = ctrl . waitFor ( [ ...TestController . INIT_SEQUENCE , State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
575+ ctrl . run ( { message : '1' , autoSend : true } ) ;
576+ await p ;
577+
578+
579+ assert . strictEqual ( model . getValue ( ) , 'eins\nHello\nWorld\nHello Again\nHello World\n' ) ;
580+
581+ const targetModel = chatService . startSession ( ChatAgentLocation . Editor , CancellationToken . None ) ! ;
582+ store . add ( targetModel ) ;
583+ chatWidget = new class extends mock < IChatWidget > ( ) {
584+ override get viewModel ( ) {
585+ return { model : targetModel } as any ;
586+ }
587+ override focusLastMessage ( ) { }
588+ } ;
589+
590+ const r = ctrl . joinCurrentRun ( ) ;
591+ await ctrl . viewInChat ( ) ;
592+
593+ assert . strictEqual ( model . getValue ( ) , 'Hello\nWorld\nHello Again\nHello World\n' ) ;
594+ await r ;
595+ } ) ;
596+
597+ test ( 'moving inline chat to another model undoes changes (2 requests)' , async function ( ) {
598+ const text = [
599+ 'eins\n' ,
600+ 'zwei\n'
601+ ] ;
602+
603+ store . add ( chatAgentService . registerDynamicAgent ( {
604+ id : 'testEditorAgent2' ,
605+ ...agentData
606+ } , {
607+ async invoke ( request , progress , history , token ) {
608+ progress ( { kind : 'textEdit' , uri : model . uri , edits : [ { range : new Range ( 1 , 1 , 1 , 1 ) , text : text . shift ( ) ?? '' } ] } ) ;
609+ return { } ;
610+ } ,
611+ } ) ) ;
612+ ctrl = instaService . createInstance ( TestController , editor ) ;
613+
614+ // REQUEST 1
615+ const p = ctrl . waitFor ( [ ...TestController . INIT_SEQUENCE , State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
616+ ctrl . run ( { message : '1' , autoSend : true } ) ;
617+ await p ;
618+
619+ assert . strictEqual ( model . getValue ( ) , 'eins\nHello\nWorld\nHello Again\nHello World\n' ) ;
620+
621+ // REQUEST 2
622+ const p2 = ctrl . waitFor ( [ State . SHOW_REQUEST , State . SHOW_RESPONSE , State . WAIT_FOR_INPUT ] ) ;
623+ await ctrl . acceptInput ( ) ;
624+ await p2 ;
625+
626+ assert . strictEqual ( model . getValue ( ) , 'zwei\neins\nHello\nWorld\nHello Again\nHello World\n' ) ;
627+
628+ const targetModel = chatService . startSession ( ChatAgentLocation . Editor , CancellationToken . None ) ! ;
629+ store . add ( targetModel ) ;
630+ chatWidget = new class extends mock < IChatWidget > ( ) {
631+ override get viewModel ( ) {
632+ return { model : targetModel } as any ;
633+ }
634+ override focusLastMessage ( ) { }
635+ } ;
636+
637+ const r = ctrl . joinCurrentRun ( ) ;
638+
639+ await ctrl . viewInChat ( ) ;
640+
641+ assert . strictEqual ( model . getValue ( ) , 'Hello\nWorld\nHello Again\nHello World\n' ) ;
642+
643+ await r ;
644+ } ) ;
497645} ) ;
0 commit comments