@@ -13,7 +13,6 @@ import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'v
1313import { StopWatch } from 'vs/base/common/stopwatch' ;
1414import { assertType } from 'vs/base/common/types' ;
1515import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
16- import { EditOperation } from 'vs/editor/common/core/editOperation' ;
1716import { IPosition , Position } from 'vs/editor/common/core/position' ;
1817import { IRange , Range } from 'vs/editor/common/core/range' ;
1918import { IEditorContribution , ScrollType } from 'vs/editor/common/editorCommon' ;
@@ -31,11 +30,14 @@ import { ILogService } from 'vs/platform/log/common/log';
3130import { EditResponse , EmptyResponse , ErrorResponse , ExpansionState , IInlineChatSessionService , MarkdownResponse , Session , SessionExchange , SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession' ;
3231import { EditModeStrategy , LivePreviewStrategy , LiveStrategy , PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies' ;
3332import { 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' ;
3534import { IChatAccessibilityService , IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat' ;
3635import { IChatService } from 'vs/workbench/contrib/chat/common/chatService' ;
3736import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding' ;
3837import { 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' ;
3941
4042export const enum State {
4143 CREATE_SESSION = 'CREATE_SESSION' ,
@@ -465,13 +467,31 @@ export class InlineChatController implements IEditorContribution {
465467
466468 const sw = StopWatch . create ( ) ;
467469 const request : IInlineChatRequest = {
470+ requestId : generateUuid ( ) ,
468471 prompt : this . _activeSession . lastInput . value ,
469472 attempt : this . _activeSession . lastInput . attempt ,
470473 selection : this . _editor . getSelection ( ) ,
471474 wholeRange : this . _activeSession . wholeRange . value ,
475+ live : this . _activeSession . editMode !== EditMode . Preview // TODO@jrieken let extension know what document is used for previewing
472476 } ;
473477 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 ) ;
475495 this . _log ( 'request started' , this . _activeSession . provider . debugName , this . _activeSession . session , request ) ;
476496
477497 let response : EditResponse | MarkdownResponse | ErrorResponse | EmptyResponse ;
@@ -482,10 +502,14 @@ export class InlineChatController implements IEditorContribution {
482502 this . _ctxHasActiveRequest . set ( true ) ;
483503 reply = await raceCancellationError ( Promise . resolve ( task ) , requestCts . token ) ;
484504
485- if ( reply ?. type === 'message' ) {
505+ if ( reply ?. type === InlineChatResponseType . Message ) {
486506 response = new MarkdownResponse ( this . _activeSession . textModelN . uri , reply ) ;
487507 } 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 ;
489513 } else {
490514 response = new EmptyResponse ( ) ;
491515 }
@@ -531,27 +555,41 @@ export class InlineChatController implements IEditorContribution {
531555 if ( ! canContinue ) {
532556 return State . ACCEPT ;
533557 }
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 ) ;
537565
566+ if ( allEdits . length === 0 ) {
567+ return ;
568+ }
569+
570+ // diff-changes from model0 -> modelN+1
571+ for ( const edits of allEdits ) {
538572 const textModelNplus1 = this . _modelService . createModel ( createTextBufferFactoryFromSnapshot ( this . _activeSession . textModelN . createSnapshot ( ) ) , null , undefined , true ) ;
539- textModelNplus1 . applyEdits ( editOperations ) ;
573+ textModelNplus1 . applyEdits ( edits . map ( TextEdit . asEditOperation ) ) ;
540574 const diff = await this . _editorWorkerService . computeDiff ( this . _activeSession . textModel0 . uri , textModelNplus1 . uri , { ignoreTrimWhitespace : false , maxComputationTimeMs : 5000 , computeMoves : false } , 'advanced' ) ;
541575 this . _activeSession . lastTextModelChanges = diff ?. changes ?? [ ] ;
542576 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- }
552577 }
553578
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+ }
555593 }
556594
557595 private async [ State . SHOW_RESPONSE ] ( ) : Promise < State . WAIT_FOR_INPUT | State . ACCEPT > {
0 commit comments