@@ -13,7 +13,6 @@ import { Schemas } from 'vs/base/common/network';
1313import { MovingAverage } from 'vs/base/common/numbers' ;
1414import { StopWatch } from 'vs/base/common/stopwatch' ;
1515import { assertType } from 'vs/base/common/types' ;
16- import { URI } from 'vs/base/common/uri' ;
1716import { generateUuid } from 'vs/base/common/uuid' ;
1817import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser' ;
1918import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget' ;
@@ -40,11 +39,12 @@ import { IInlineChatMessageAppender, InlineChatWidget } from 'vs/workbench/contr
4039import { asProgressiveEdit , performAsyncTextEdit } from 'vs/workbench/contrib/inlineChat/browser/utils' ;
4140import { CTX_INLINE_CHAT_LAST_RESPONSE_TYPE , EditMode , IInlineChatProgressItem , IInlineChatRequest , InlineChatResponseFeedbackKind , InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
4241import { insertCell , runDeleteAction } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations' ;
43- import { CTX_NOTEBOOK_CELL_CHAT_FOCUSED , CTX_NOTEBOOK_CHAT_HAS_ACTIVE_REQUEST , MENU_CELL_CHAT_INPUT , MENU_CELL_CHAT_WIDGET , MENU_CELL_CHAT_WIDGET_FEEDBACK , MENU_CELL_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext' ;
42+ import { CTX_NOTEBOOK_CELL_CHAT_FOCUSED , CTX_NOTEBOOK_CHAT_HAS_ACTIVE_REQUEST , CTX_NOTEBOOK_CHAT_USER_DID_EDIT , MENU_CELL_CHAT_INPUT , MENU_CELL_CHAT_WIDGET , MENU_CELL_CHAT_WIDGET_FEEDBACK , MENU_CELL_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext' ;
4443import { INotebookEditor , INotebookEditorContribution , INotebookViewZone , ScrollToRevealBehavior } from 'vs/workbench/contrib/notebook/browser/notebookBrowser' ;
4544import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions' ;
4645import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl' ;
4746import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
47+ import { INotebookExecutionStateService , NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService' ;
4848
4949
5050
@@ -100,10 +100,21 @@ class NotebookChatWidget extends Disposable implements INotebookViewZone {
100100 this . inlineChatWidget . focus ( ) ;
101101 }
102102
103- async getEditingCellEditor ( ) {
103+ getEditingCell ( ) {
104+ return this . _editingCell ;
105+ }
106+
107+ async getOrCreateEditingCell ( ) : Promise < { cell : CellViewModel ; editor : IActiveCodeEditor } | undefined > {
104108 if ( this . _editingCell ) {
105109 await this . _notebookEditor . focusNotebookCell ( this . _editingCell , 'editor' ) ;
106- return this . _notebookEditor . activeCodeEditor ;
110+ if ( this . _notebookEditor . activeCodeEditor ?. hasModel ( ) ) {
111+ return {
112+ cell : this . _editingCell ,
113+ editor : this . _notebookEditor . activeCodeEditor
114+ } ;
115+ } else {
116+ return undefined ;
117+ }
107118 }
108119
109120 if ( ! this . _notebookEditor . hasModel ( ) ) {
@@ -117,7 +128,14 @@ class NotebookChatWidget extends Disposable implements INotebookViewZone {
117128 }
118129
119130 await this . _notebookEditor . focusNotebookCell ( this . _editingCell , 'editor' , { revealBehavior : ScrollToRevealBehavior . firstLine } ) ;
120- return this . _notebookEditor . activeCodeEditor ;
131+ if ( this . _notebookEditor . activeCodeEditor ?. hasModel ( ) ) {
132+ return {
133+ cell : this . _editingCell ,
134+ editor : this . _notebookEditor . activeCodeEditor
135+ } ;
136+ }
137+
138+ return undefined ;
121139 }
122140
123141 async discardChange ( ) {
@@ -160,6 +178,8 @@ export class NotebookChatController extends Disposable implements INotebookEdito
160178 private _activeSession ?: Session ;
161179 private readonly _ctxHasActiveRequest : IContextKey < boolean > ;
162180 private readonly _ctxCellWidgetFocused : IContextKey < boolean > ;
181+ private readonly _ctxUserDidEdit : IContextKey < boolean > ;
182+ private readonly _userEditingDisposables = this . _register ( new DisposableStore ( ) ) ;
163183 private readonly _ctxLastResponseType : IContextKey < undefined | InlineChatResponseType > ;
164184 private _widget : NotebookChatWidget | undefined ;
165185 private _widgetDisposableStore = this . _register ( new DisposableStore ( ) ) ;
@@ -174,12 +194,14 @@ export class NotebookChatController extends Disposable implements INotebookEdito
174194 @IInlineChatSavingService private readonly _inlineChatSavingService : IInlineChatSavingService ,
175195 @IModelService private readonly _modelService : IModelService ,
176196 @ILanguageService private readonly _languageService : ILanguageService ,
197+ @INotebookExecutionStateService private _executionStateService : INotebookExecutionStateService ,
177198
178199 ) {
179200 super ( ) ;
180201 this . _ctxHasActiveRequest = CTX_NOTEBOOK_CHAT_HAS_ACTIVE_REQUEST . bindTo ( this . _contextKeyService ) ;
181202 this . _ctxCellWidgetFocused = CTX_NOTEBOOK_CELL_CHAT_FOCUSED . bindTo ( this . _contextKeyService ) ;
182203 this . _ctxLastResponseType = CTX_INLINE_CHAT_LAST_RESPONSE_TYPE . bindTo ( this . _contextKeyService ) ;
204+ this . _ctxUserDidEdit = CTX_NOTEBOOK_CHAT_USER_DID_EDIT . bindTo ( this . _contextKeyService ) ;
183205 }
184206
185207 run ( index : number , input : string | undefined , autoSend : boolean | undefined ) : void {
@@ -206,6 +228,10 @@ export class NotebookChatController extends Disposable implements INotebookEdito
206228 }
207229
208230 private _createWidget ( index : number , input : string | undefined , autoSend : boolean | undefined ) {
231+ if ( ! this . _notebookEditor . hasModel ( ) ) {
232+ return ;
233+ }
234+
209235 // Clear the widget if it's already there
210236 this . _widgetDisposableStore . clear ( ) ;
211237
@@ -230,8 +256,9 @@ export class NotebookChatController extends Disposable implements INotebookEdito
230256 { isSimpleWidget : true }
231257 ) ) ;
232258
233- const inputBoxPath = `/notebook-chat-input-${ NotebookChatController . counter ++ } ` ;
234- const inputUri = URI . from ( { scheme : Schemas . untitled , path : inputBoxPath } ) ;
259+ const inputBoxFragment = `notebook-chat-input-${ NotebookChatController . counter ++ } ` ;
260+ const notebookUri = this . _notebookEditor . textModel . uri ;
261+ const inputUri = notebookUri . with ( { scheme : Schemas . untitled , fragment : inputBoxFragment } ) ;
235262 const result : ITextModel = this . _modelService . createModel ( '' , null , inputUri , false ) ;
236263 fakeParentEditor . setModel ( result ) ;
237264
@@ -270,8 +297,9 @@ export class NotebookChatController extends Disposable implements INotebookEdito
270297 this . _languageService
271298 ) ;
272299
300+ this . _ctxCellWidgetFocused . set ( true ) ;
301+
273302 disposableTimeout ( ( ) => {
274- this . _ctxCellWidgetFocused . set ( true ) ;
275303 this . _focusWidget ( ) ;
276304 } , 0 , this . _store ) ;
277305
@@ -330,6 +358,7 @@ export class NotebookChatController extends Disposable implements INotebookEdito
330358 }
331359
332360 this . _notebookEditor . focusContainer ( true ) ;
361+ this . _notebookEditor . setFocus ( { start : this . _widget . afterModelPosition , end : this . _widget . afterModelPosition } ) ;
333362 this . _notebookEditor . setSelections ( [ {
334363 start : this . _widget . afterModelPosition ,
335364 end : this . _widget . afterModelPosition
@@ -476,6 +505,22 @@ export class NotebookChatController extends Disposable implements INotebookEdito
476505 } ) ;
477506 }
478507 }
508+
509+ this . _userEditingDisposables . clear ( ) ;
510+ // monitor user edits
511+ const editingCell = this . _widget . getEditingCell ( ) ;
512+ if ( editingCell ) {
513+ this . _userEditingDisposables . add ( editingCell . model . onDidChangeContent ( ( ) => this . _updateUserEditingState ( ) ) ) ;
514+ this . _userEditingDisposables . add ( editingCell . model . onDidChangeLanguage ( ( ) => this . _updateUserEditingState ( ) ) ) ;
515+ this . _userEditingDisposables . add ( editingCell . model . onDidChangeMetadata ( ( ) => this . _updateUserEditingState ( ) ) ) ;
516+ this . _userEditingDisposables . add ( editingCell . model . onDidChangeInternalMetadata ( ( ) => this . _updateUserEditingState ( ) ) ) ;
517+ this . _userEditingDisposables . add ( editingCell . model . onDidChangeOutputs ( ( ) => this . _updateUserEditingState ( ) ) ) ;
518+ this . _userEditingDisposables . add ( this . _executionStateService . onDidChangeExecution ( e => {
519+ if ( e . type === NotebookExecutionType . cell && e . affectsCell ( editingCell . uri ) ) {
520+ this . _updateUserEditingState ( ) ;
521+ }
522+ } ) ) ;
523+ }
479524 }
480525 } catch ( e ) {
481526 response = new ErrorResponse ( e ) ;
@@ -519,12 +564,14 @@ export class NotebookChatController extends Disposable implements INotebookEdito
519564 assertType ( this . _strategy ) ;
520565 assertType ( this . _widget ) ;
521566
522- const editor = await this . _widget . getEditingCellEditor ( ) ;
567+ const editingCell = await this . _widget . getOrCreateEditingCell ( ) ;
523568
524- if ( ! editor || ! editor . hasModel ( ) ) {
569+ if ( ! editingCell ) {
525570 return ;
526571 }
527572
573+ const editor = editingCell . editor ;
574+
528575 const moreMinimalEdits = await this . _editorWorkerService . computeMoreMinimalEdits ( editor . getModel ( ) . uri , edits ) ;
529576 // this._log('edits from PROVIDER and after making them MORE MINIMAL', this._activeSession.provider.debugName, edits, moreMinimalEdits);
530577
@@ -551,6 +598,10 @@ export class NotebookChatController extends Disposable implements INotebookEdito
551598 }
552599 }
553600
601+ private _updateUserEditingState ( ) {
602+ this . _ctxUserDidEdit . set ( true ) ;
603+ }
604+
554605 async acceptSession ( ) {
555606 assertType ( this . _activeSession ) ;
556607 assertType ( this . _strategy ) ;
@@ -615,6 +666,7 @@ export class NotebookChatController extends Disposable implements INotebookEdito
615666 discard ( ) {
616667 this . _strategy ?. cancel ( ) ;
617668 this . _widget ?. discardChange ( ) ;
669+ this . dismiss ( ) ;
618670 }
619671
620672 async feedbackLast ( kind : InlineChatResponseFeedbackKind ) {
@@ -627,6 +679,7 @@ export class NotebookChatController extends Disposable implements INotebookEdito
627679
628680 dismiss ( ) {
629681 this . _ctxCellWidgetFocused . set ( false ) ;
682+ this . _ctxUserDidEdit . set ( false ) ;
630683 this . _sessionCtor ?. cancel ( ) ;
631684 this . _sessionCtor = undefined ;
632685 this . _widget ?. dispose ( ) ;
0 commit comments