diff --git a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController.ts b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController.ts index 5f2594d2e975f..105658abefb1b 100644 --- a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController.ts +++ b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController.ts @@ -321,12 +321,13 @@ export class InteractiveEditorController implements IEditorContribution { @IContextKeyService contextKeyService: IContextKeyService, ) { - this._zone = this._store.add(_instaService.createInstance(InteractiveEditorZoneWidget, this._editor)); this._ctxHasActiveRequest = CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST.bindTo(contextKeyService); this._ctxInlineDiff = CTX_INTERACTIVE_EDITOR_INLNE_DIFF.bindTo(contextKeyService); this._ctxLastEditKind = CTX_INTERACTIVE_EDITOR_LAST_EDIT_KIND.bindTo(contextKeyService); this._ctxLastResponseType = CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.bindTo(contextKeyService); this._ctxLastFeedbackKind = CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK_KIND.bindTo(contextKeyService); + this._zone = this._store.add(_instaService.createInstance(InteractiveEditorZoneWidget, this._editor)); + } dispose(): void { @@ -474,6 +475,8 @@ export class InteractiveEditorController implements IEditorContribution { const diffZone = this._instaService.createInstance(InteractiveEditorDiffWidget, this._editor, textModel0); + let _requestCancelledOnModelContentChanged = false; + do { const wholeRange = wholeRangeDecoration.getRange(0); @@ -494,7 +497,8 @@ export class InteractiveEditorController implements IEditorContribution { this._ctsRequest = new CancellationTokenSource(this._ctsSession.token); this._historyOffset = -1; - const inputPromise = this._zone.getInput(wholeRange.getEndPosition(), placeholder, value, this._ctsRequest.token); + const inputPromise = this._zone.getInput(wholeRange.getEndPosition(), placeholder, value, this._ctsRequest.token, _requestCancelledOnModelContentChanged); + _requestCancelledOnModelContentChanged = false; if (textModel0Changes && editMode === EditMode.LivePreview) { @@ -528,6 +532,11 @@ export class InteractiveEditorController implements IEditorContribution { continue; } + const typeListener = this._zone.widget.inputEditor.onDidChangeModelContent(() => { + this.cancelCurrentRequest(); + _requestCancelledOnModelContentChanged = true; + }); + const sw = StopWatch.create(); const request: IInteractiveEditorRequest = { prompt: input, @@ -557,6 +566,8 @@ export class InteractiveEditorController implements IEditorContribution { this._ctxLastResponseType.set(reply?.type); this._zone.widget.updateProgress(false); this._logService.trace('[IE] request took', sw.elapsed(), provider.debugName); + + typeListener.dispose(); } if (this._ctsRequest.token.isCancellationRequested) { diff --git a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorWidget.ts b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorWidget.ts index 98476cf877b95..5b69f7ef24b03 100644 --- a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorWidget.ts +++ b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorWidget.ts @@ -28,7 +28,7 @@ import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/br import { HiddenItemStrategy, MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController'; -import { IPosition } from 'vs/editor/common/core/position'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style'; import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { TextEdit } from 'vs/editor/common/languages'; @@ -286,14 +286,23 @@ class InteractiveEditorWidget { } } - getInput(placeholder: string, value: string, token: CancellationToken): Promise { + getInput(placeholder: string, value: string, token: CancellationToken, requestCancelledOnModelContentChanged: boolean): Promise { + + const currentInputEditorPosition = this.inputEditor.getPosition(); + const currentInputEditorValue = this.inputEditor.getValue(); this._elements.placeholder.innerText = placeholder; this._elements.placeholder.style.fontSize = `${this.inputEditor.getOption(EditorOption.fontSize)}px`; this._elements.placeholder.style.lineHeight = `${this.inputEditor.getOption(EditorOption.lineHeight)}px`; - this._inputModel.setValue(value); - this.inputEditor.setSelection(this._inputModel.getFullModelRange()); + this._inputModel.setValue(requestCancelledOnModelContentChanged ? currentInputEditorValue : value); + const fullInputModelRange = this._inputModel.getFullModelRange(); + + if (requestCancelledOnModelContentChanged) { + this.inputEditor.setPosition(currentInputEditorPosition ?? new Position(fullInputModelRange.endLineNumber, fullInputModelRange.endColumn)); + } else { + this.inputEditor.setSelection(fullInputModelRange); + } this.inputEditor.updateOptions({ ariaLabel: localize('aria-label.N', "Interactive Editor Input: {0}", placeholder) }); const disposeOnDone = new DisposableStore(); @@ -575,12 +584,12 @@ export class InteractiveEditorZoneWidget extends ZoneWidget { super._relayout(this._computeHeightInLines()); } - async getInput(where: IPosition, placeholder: string, value: string, token: CancellationToken): Promise { + async getInput(where: IPosition, placeholder: string, value: string, token: CancellationToken, requestCancelledOnModelContentChanged: boolean): Promise { assertType(this.editor.hasModel()); super.show(where, this._computeHeightInLines()); this._ctxVisible.set(true); - const task = this.widget.getInput(placeholder, value, token); + const task = this.widget.getInput(placeholder, value, token, requestCancelledOnModelContentChanged); const result = await task; return result; }