diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index d883e5170a6..49a3f4bfbd3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -67,6 +67,7 @@ export interface InteractiveEditorRunOptions { autoSend?: boolean; existingSession?: Session; isUnstashed?: boolean; + initialRender?: boolean; } export class InteractiveEditorController implements IEditorContribution { @@ -99,6 +100,8 @@ export class InteractiveEditorController implements IEditorContribution { private _activeSession?: Session; private _strategy?: EditModeStrategy; private _ignoreModelContentChanged = false; + private _initialRender?: boolean = true; + private _updateEditMode?: boolean = false; constructor( private readonly _editor: ICodeEditor, @@ -232,26 +235,55 @@ export class InteractiveEditorController implements IEditorContribution { return State.CANCEL; } + this._initializeStratetgy(session); + this._activeSession = session; + this._store.add(this._configurationService.onDidChangeConfiguration((e) => { + console.log('e : ', e); + console.log('e.affectsConfiguration(interactiveEditor.editModes) : ', e.affectsConfiguration('interactiveEditor.editMode')); + console.log('this._activeSession : ', this._activeSession); + if (e.affectsConfiguration('interactiveEditor.editMode')) { + console.log('entered into inner if loop of onDidChangeConfiguration'); + console.log('this._getMode() : ', this._getMode()); + this._updateEditMode = true; + } + })); + + return State.INIT_UI; + } + + private _initializeStratetgy(session: Session): void { + console.log('inside of initial strategy'); switch (session.editMode) { case EditMode.Live: this._strategy = this._instaService.createInstance(LiveStrategy, session, this._editor, this._zone.value.widget); break; case EditMode.Preview: - this._strategy = this._instaService.createInstance(PreviewStrategy, session, this._zone.value.widget); + this._strategy = this._instaService.createInstance(PreviewStrategy, session, this._editor, this._zone.value.widget); break; case EditMode.LivePreview: default: this._strategy = this._instaService.createInstance(LivePreviewStrategy, session, this._editor, this._zone.value.widget); break; } + } - this._activeSession = session; - return State.INIT_UI; + private _showWidget(initialRender: boolean = false) { + console.log('inside of _showWidget'); + console.log('initialRender : ', initialRender); + assertType(this._activeSession); + const selectionRange = this._activeSession.wholeRange.value; + this._zone.value.showWidget(selectionRange, this._strategy?.getWidgetPosition(initialRender, selectionRange)); } private async [State.INIT_UI](options: InteractiveEditorRunOptions | undefined): Promise { assertType(this._activeSession); + if (this._updateEditMode) { + this._activeSession.editMode = this._getMode(); + this._initializeStratetgy(this._activeSession); + this._updateEditMode = false; + } + // hide/cancel inline completions when invoking IE InlineCompletionsController.get(this._editor)?.hide(); @@ -269,8 +301,10 @@ export class InteractiveEditorController implements IEditorContribution { this._zone.value.widget.placeholder = this._getPlaceholderText(); this._zone.value.widget.value = this._activeSession.lastInput ?? ''; this._zone.value.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect")); - this._zone.value.show(this._activeSession.wholeRange.value); this._zone.value.widget.preferredExpansionState = this._activeSession.lastExpansionState; + console.log('inside of init ui before show widget'); + this._initialRender = true; + this._showWidget(this._initialRender); this._sessionStore.add(this._editor.onDidChangeModel((e) => { const msg = this._activeSession?.lastExchange @@ -358,8 +392,10 @@ export class InteractiveEditorController implements IEditorContribution { private async [State.WAIT_FOR_INPUT](options: InteractiveEditorRunOptions | undefined): Promise { assertType(this._activeSession); + console.log('inside of wait for input'); this._zone.value.widget.placeholder = this._getPlaceholderText(); - this._zone.value.show(this._activeSession.wholeRange.value); + this._showWidget(this._initialRender); + this._initialRender = false; if (options?.message) { this._zone.value.widget.value = options?.message; @@ -398,6 +434,7 @@ export class InteractiveEditorController implements IEditorContribution { } if (!this._zone.value.widget.value) { + console.log('before the case when we call WAIT_FOR_INPUT'); return State.WAIT_FOR_INPUT; } @@ -427,6 +464,7 @@ export class InteractiveEditorController implements IEditorContribution { private async [State.MAKE_REQUEST](): Promise { assertType(this._editor.hasModel()); assertType(this._activeSession); + console.log('this._activeSession.lastInput : ', this._activeSession.lastInput); assertType(this._activeSession.lastInput); const requestCts = new CancellationTokenSource(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index c45dd008972..4a3a5e077b9 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -120,7 +120,7 @@ export class Session { private _textModelNSnapshotAltVersion: number | undefined; constructor( - readonly editMode: EditMode, + public editMode: EditMode, readonly editor: ICodeEditor, readonly textModel0: ITextModel, readonly textModelN: ITextModel, diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index d57c6e7d862..5289f91c2c7 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -41,7 +41,28 @@ export abstract class EditModeStrategy { abstract toggleDiff(): void; - abstract getWidgetPosition(range: Range): Position; + abstract getWidgetPosition(initialRender: boolean, range: Range): Position | undefined; +} + +function positionCalculation(editor: ICodeEditor, initialRender: boolean, range: Range): Position | undefined { + const viewModel = editor._getViewModel(); + if (!viewModel) { + return; + } + const primaryCursorPosition = viewModel.getPrimaryCursorState().viewState.position; + if (initialRender) { + return primaryCursorPosition; + } else { + const visibleRange = viewModel.getCompletelyVisibleViewRange(); + const endPosition = range.getEndPosition(); + const endLine = endPosition.lineNumber; + + if (endLine >= visibleRange.startLineNumber && endLine <= visibleRange.endLineNumber) { + return endPosition; + } else { + return primaryCursorPosition; + } + } } export class PreviewStrategy extends EditModeStrategy { @@ -51,6 +72,7 @@ export class PreviewStrategy extends EditModeStrategy { constructor( private readonly _session: Session, + private readonly _editor: ICodeEditor, private readonly _widget: InteractiveEditorWidget, @IContextKeyService contextKeyService: IContextKeyService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, @@ -129,8 +151,9 @@ export class PreviewStrategy extends EditModeStrategy { // nothing to do } - getWidgetPosition(range: Range): Position { - throw new Error('not supported'); + getWidgetPosition(initialRender: boolean, range: Range): Position | undefined { + console.log('inside of preview strategy, getWidgetPosition'); + return positionCalculation(this._editor, initialRender, range); } } @@ -325,8 +348,9 @@ export class LiveStrategy extends EditModeStrategy { this._widget.updateStatus(message); } - getWidgetPosition(range: Range): Position { - throw new Error('not supported'); + getWidgetPosition(initialRender: boolean, range: Range): Position | undefined { + console.log('inside of live strategy, getWidgetPosition'); + return positionCalculation(this._editor, initialRender, range); } } @@ -383,8 +407,13 @@ export class LivePreviewStrategy extends LiveStrategy { scrollState.restore(this._editor); } - override getWidgetPosition(range: Range): Position { - throw new Error('not supported'); + override getWidgetPosition(initialRender: boolean, range: Range): Position | undefined { + console.log('inside of live preview strategy, getWidgetPosition'); + if (initialRender) { + return this._editor._getViewModel()?.getPrimaryCursorState().viewState.position; + } else { + return range.getEndPosition(); + } } } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index 8932df9d3bb..e6320d136ed 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -787,24 +787,25 @@ export class InteractiveEditorZoneWidget extends ZoneWidget { super._relayout(this._computeHeightInLines()); } - override show(selectionRange: Range): void { - super.show(selectionRange.getEndPosition(), this._computeHeightInLines()); + showWidget(selectionRange: Range, position: Position | undefined): void { + const widgetPosition = position ?? selectionRange.getEndPosition(); + super.show(widgetPosition, this._computeHeightInLines()); this.widget.focus(); this._ctxVisible.set(true); - this._setMargins(selectionRange); + this._setMargins(selectionRange, widgetPosition); } - private _setMargins(selectionRange: Range): void { + private _setMargins(selectionRange: Range, position: Position): void { + const positionLineNumber = position.lineNumber; const info = this.editor.getLayoutInfo(); const startLineNumber = selectionRange.getStartPosition().lineNumber; - const endLineNumber = selectionRange.getEndPosition().lineNumber; const viewModel = this.editor._getViewModel(); if (!viewModel) { return; } let indentationLineNumber; let indentationLevel; - for (let lineNumber = endLineNumber; lineNumber >= startLineNumber; lineNumber--) { + for (let lineNumber = positionLineNumber; lineNumber >= startLineNumber; lineNumber--) { const currentIndentationLevel = viewModel.getLineFirstNonWhitespaceColumn(lineNumber); if (currentIndentationLevel !== 0) { indentationLineNumber = lineNumber; @@ -812,7 +813,7 @@ export class InteractiveEditorZoneWidget extends ZoneWidget { break; } } - this._indentationWidth = this.editor.getOffsetForColumn(indentationLineNumber ?? endLineNumber, indentationLevel ?? viewModel.getLineFirstNonWhitespaceColumn(endLineNumber)); + this._indentationWidth = this.editor.getOffsetForColumn(indentationLineNumber ?? positionLineNumber, indentationLevel ?? viewModel.getLineFirstNonWhitespaceColumn(positionLineNumber)); const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth; const marginWithIndentation = marginWithoutIndentation + this._indentationWidth; const isEnoughAvailableSpaceWithIndentation = this._availableSpaceGivenIndentation() > 400;