@@ -13,7 +13,6 @@ import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'v
13
13
import { StopWatch } from 'vs/base/common/stopwatch' ;
14
14
import { assertType } from 'vs/base/common/types' ;
15
15
import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
16
- import { EditOperation } from 'vs/editor/common/core/editOperation' ;
17
16
import { IPosition , Position } from 'vs/editor/common/core/position' ;
18
17
import { IRange , Range } from 'vs/editor/common/core/range' ;
19
18
import { IEditorContribution , ScrollType } from 'vs/editor/common/editorCommon' ;
@@ -31,11 +30,14 @@ import { ILogService } from 'vs/platform/log/common/log';
31
30
import { EditResponse , EmptyResponse , ErrorResponse , ExpansionState , IInlineChatSessionService , MarkdownResponse , Session , SessionExchange , SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession' ;
32
31
import { EditModeStrategy , LivePreviewStrategy , LiveStrategy , PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies' ;
33
32
import { InlineChatZoneWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget' ;
34
- import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST , CTX_INLINE_CHAT_LAST_FEEDBACK , IInlineChatRequest , IInlineChatResponse , INLINE_CHAT_ID , EditMode , InlineChatResponseFeedbackKind , CTX_INLINE_CHAT_LAST_RESPONSE_TYPE , InlineChatResponseType , CTX_INLINE_CHAT_DID_EDIT , CTX_INLINE_CHAT_HAS_STASHED_SESSION , InlineChateResponseTypes , CTX_INLINE_CHAT_RESPONSE_TYPES , CTX_INLINE_CHAT_USER_DID_EDIT } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
33
+ import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST , CTX_INLINE_CHAT_LAST_FEEDBACK , IInlineChatRequest , IInlineChatResponse , INLINE_CHAT_ID , EditMode , InlineChatResponseFeedbackKind , CTX_INLINE_CHAT_LAST_RESPONSE_TYPE , InlineChatResponseType , CTX_INLINE_CHAT_DID_EDIT , CTX_INLINE_CHAT_HAS_STASHED_SESSION , InlineChateResponseTypes , CTX_INLINE_CHAT_RESPONSE_TYPES , CTX_INLINE_CHAT_USER_DID_EDIT , IInlineChatProgressItem } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
35
34
import { IChatAccessibilityService , IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat' ;
36
35
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService' ;
37
36
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding' ;
38
37
import { Lazy } from 'vs/base/common/lazy' ;
38
+ import { Progress } from 'vs/platform/progress/common/progress' ;
39
+ import { generateUuid } from 'vs/base/common/uuid' ;
40
+ import { TextEdit } from 'vs/editor/common/languages' ;
39
41
40
42
export const enum State {
41
43
CREATE_SESSION = 'CREATE_SESSION' ,
@@ -465,13 +467,31 @@ export class InlineChatController implements IEditorContribution {
465
467
466
468
const sw = StopWatch . create ( ) ;
467
469
const request : IInlineChatRequest = {
470
+ requestId : generateUuid ( ) ,
468
471
prompt : this . _activeSession . lastInput . value ,
469
472
attempt : this . _activeSession . lastInput . attempt ,
470
473
selection : this . _editor . getSelection ( ) ,
471
474
wholeRange : this . _activeSession . wholeRange . value ,
475
+ live : this . _activeSession . editMode !== EditMode . Preview // TODO@jrieken let extension know what document is used for previewing
472
476
} ;
473
477
this . _chatAccessibilityService . acceptRequest ( ) ;
474
- const task = this . _activeSession . provider . provideResponse ( this . _activeSession . session , request , requestCts . token ) ;
478
+
479
+ const progressEdits : TextEdit [ ] [ ] = [ ] ;
480
+ const progress = new Progress < IInlineChatProgressItem > ( async data => {
481
+ this . _log ( 'received chunk' , data , request ) ;
482
+ if ( ! request . live ) {
483
+ throw new Error ( 'Progress in NOT supported in non-live mode' ) ;
484
+ }
485
+ if ( data . message ) {
486
+ this . _zone . value . widget . updateToolbar ( false ) ;
487
+ this . _zone . value . widget . updateInfo ( data . message ) ;
488
+ }
489
+ if ( data . edits ) {
490
+ progressEdits . push ( data . edits ) ;
491
+ await this . _makeChanges ( progressEdits ) ;
492
+ }
493
+ } , { async : true } ) ;
494
+ const task = this . _activeSession . provider . provideResponse ( this . _activeSession . session , request , progress , requestCts . token ) ;
475
495
this . _log ( 'request started' , this . _activeSession . provider . debugName , this . _activeSession . session , request ) ;
476
496
477
497
let response : EditResponse | MarkdownResponse | ErrorResponse | EmptyResponse ;
@@ -482,10 +502,14 @@ export class InlineChatController implements IEditorContribution {
482
502
this . _ctxHasActiveRequest . set ( true ) ;
483
503
reply = await raceCancellationError ( Promise . resolve ( task ) , requestCts . token ) ;
484
504
485
- if ( reply ?. type === 'message' ) {
505
+ if ( reply ?. type === InlineChatResponseType . Message ) {
486
506
response = new MarkdownResponse ( this . _activeSession . textModelN . uri , reply ) ;
487
507
} else if ( reply ) {
488
- response = new EditResponse ( this . _activeSession . textModelN . uri , this . _activeSession . textModelN . getAlternativeVersionId ( ) , reply ) ;
508
+ const editResponse = new EditResponse ( this . _activeSession . textModelN . uri , this . _activeSession . textModelN . getAlternativeVersionId ( ) , reply , progressEdits ) ;
509
+ if ( editResponse . allLocalEdits . length > progressEdits . length ) {
510
+ await this . _makeChanges ( editResponse . allLocalEdits ) ;
511
+ }
512
+ response = editResponse ;
489
513
} else {
490
514
response = new EmptyResponse ( ) ;
491
515
}
@@ -531,27 +555,41 @@ export class InlineChatController implements IEditorContribution {
531
555
if ( ! canContinue ) {
532
556
return State . ACCEPT ;
533
557
}
534
- const moreMinimalEdits = ( await this . _editorWorkerService . computeHumanReadableDiff ( this . _activeSession . textModelN . uri , response . localEdits ) ) ;
535
- const editOperations = ( moreMinimalEdits ?? response . localEdits ) . map ( edit => EditOperation . replace ( Range . lift ( edit . range ) , edit . text ) ) ;
536
- this . _log ( 'edits from PROVIDER and after making them MORE MINIMAL' , this . _activeSession . provider . debugName , response . localEdits , moreMinimalEdits ) ;
558
+ }
559
+ return State . SHOW_RESPONSE ;
560
+ }
561
+
562
+ private async _makeChanges ( allEdits : TextEdit [ ] [ ] ) {
563
+ assertType ( this . _activeSession ) ;
564
+ assertType ( this . _strategy ) ;
537
565
566
+ if ( allEdits . length === 0 ) {
567
+ return ;
568
+ }
569
+
570
+ // diff-changes from model0 -> modelN+1
571
+ for ( const edits of allEdits ) {
538
572
const textModelNplus1 = this . _modelService . createModel ( createTextBufferFactoryFromSnapshot ( this . _activeSession . textModelN . createSnapshot ( ) ) , null , undefined , true ) ;
539
- textModelNplus1 . applyEdits ( editOperations ) ;
573
+ textModelNplus1 . applyEdits ( edits . map ( TextEdit . asEditOperation ) ) ;
540
574
const diff = await this . _editorWorkerService . computeDiff ( this . _activeSession . textModel0 . uri , textModelNplus1 . uri , { ignoreTrimWhitespace : false , maxComputationTimeMs : 5000 , computeMoves : false } , 'advanced' ) ;
541
575
this . _activeSession . lastTextModelChanges = diff ?. changes ?? [ ] ;
542
576
textModelNplus1 . dispose ( ) ;
543
-
544
- try {
545
- this . _ignoreModelContentChanged = true ;
546
- this . _activeSession . wholeRange . trackEdits ( editOperations ) ;
547
- await this . _strategy . makeChanges ( editOperations ) ;
548
- this . _ctxDidEdit . set ( this . _activeSession . hasChangedText ) ;
549
- } finally {
550
- this . _ignoreModelContentChanged = false ;
551
- }
552
577
}
553
578
554
- return State . SHOW_RESPONSE ;
579
+ // make changes from modelN -> modelN+1
580
+ const lastEdits = allEdits [ allEdits . length - 1 ] ;
581
+ const moreMinimalEdits = await this . _editorWorkerService . computeHumanReadableDiff ( this . _activeSession . textModelN . uri , lastEdits ) ;
582
+ const editOperations = ( moreMinimalEdits ?? lastEdits ) . map ( TextEdit . asEditOperation ) ;
583
+ this . _log ( 'edits from PROVIDER and after making them MORE MINIMAL' , this . _activeSession . provider . debugName , lastEdits , moreMinimalEdits ) ;
584
+
585
+ try {
586
+ this . _ignoreModelContentChanged = true ;
587
+ this . _activeSession . wholeRange . trackEdits ( editOperations ) ;
588
+ await this . _strategy . makeChanges ( editOperations ) ;
589
+ this . _ctxDidEdit . set ( this . _activeSession . hasChangedText ) ;
590
+ } finally {
591
+ this . _ignoreModelContentChanged = false ;
592
+ }
555
593
}
556
594
557
595
private async [ State . SHOW_RESPONSE ] ( ) : Promise < State . WAIT_FOR_INPUT | State . ACCEPT > {
0 commit comments