diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts index a90172eacd107..a4255e29f0d33 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts @@ -19,18 +19,14 @@ import { TextEdit } from '../../../../../editor/common/languages.js'; import { ITextModelService } from '../../../../../editor/common/services/resolverService.js'; import { localize, localize2 } from '../../../../../nls.js'; import { IContextKey, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; -import { EditorActivation } from '../../../../../platform/editor/common/editor.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { bindContextKey } from '../../../../../platform/observable/common/platformObservableUtils.js'; import { IProgressService, ProgressLocation } from '../../../../../platform/progress/common/progress.js'; -import { EditorInput } from '../../../../common/editor/editorInput.js'; import { IWorkbenchAssignmentService } from '../../../../services/assignment/common/assignmentService.js'; import { IDecorationData, IDecorationsProvider, IDecorationsService } from '../../../../services/decorations/common/decorations.js'; -import { IEditorGroup, IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js'; -import { MultiDiffEditor } from '../../../multiDiffEditor/browser/multiDiffEditor.js'; import { IMultiDiffSourceResolver, IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MultiDiffEditorItem } from '../../../multiDiffEditor/browser/multiDiffSourceResolverService.js'; import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; @@ -79,7 +75,6 @@ export class ChatEditingService extends Disposable implements IChatEditingServic private _chatRelatedFilesProviders = new Map(); constructor( - @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IMultiDiffSourceResolverService multiDiffSourceResolverService: IMultiDiffSourceResolverService, @ITextModelService textModelService: ITextModelService, @@ -204,10 +199,11 @@ export class ChatEditingService extends Disposable implements IChatEditingServic this._currentSessionDisposables.clear(); + const session = this._instantiationService.createInstance(ChatEditingSession, chatSessionId, this._editingSessionFileLimitPromise); + // listen for completed responses, run the code mapper and apply the edits to this edit session - this._currentSessionDisposables.add(this.installAutoApplyObserver(chatSessionId)); + this._currentSessionDisposables.add(this.installAutoApplyObserver(session)); - const session = this._instantiationService.createInstance(ChatEditingSession, chatSessionId, this._editingSessionFileLimitPromise); await session.restoreState(); this._currentSessionDisposables.add(session.onDidDispose(() => { @@ -233,11 +229,11 @@ export class ChatEditingService extends Disposable implements IChatEditingServic await this._currentSessionObs.get()?.restoreSnapshot(requestId); } - private installAutoApplyObserver(sessionId: string): IDisposable { + private installAutoApplyObserver(session: ChatEditingSession): IDisposable { - const chatModel = this._chatService.getSession(sessionId); + const chatModel = this._chatService.getSession(session.chatSessionId); if (!chatModel) { - throw new Error(`Edit session was created for a non-existing chat session: ${sessionId}`); + throw new Error(`Edit session was created for a non-existing chat session: ${session.chatSessionId}`); } const observerDisposables = new DisposableStore(); @@ -250,7 +246,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic const onResponseComplete = (responseModel: IChatResponseModel) => { if (responseModel.result?.errorDetails && !responseModel.result.errorDetails.responseIsIncomplete) { // Roll back everything - this.restoreSnapshot(responseModel.requestId); + session.restoreSnapshot(responseModel.requestId); this._applyingChatEditsFailedContextKey.set(true); } @@ -293,7 +289,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic await editsPromise; - editsPromise = this._continueEditingSession(async (builder, token) => { + editsPromise = this._continueEditingSession(session, async (builder, token) => { for await (const item of editsSource!.asyncIterable) { if (token.isCancellationRequested) { break; @@ -304,7 +300,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic builder.textEdits(item.uri, group, isLastGroup && (item.done ?? false), responseModel); } } - }, { silent: true }).finally(() => { + }).finally(() => { editsPromise = undefined; }); } @@ -314,6 +310,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic observerDisposables.add(chatModel.onDidChange(async e => { if (e.kind === 'addRequest') { + session.createSnapshot(e.request.id); this._applyingChatEditsFailedContextKey.set(false); const responseModel = e.request.response; if (responseModel) { @@ -338,27 +335,11 @@ export class ChatEditingService extends Disposable implements IChatEditingServic return observerDisposables; } - private async _continueEditingSession(builder: (stream: IChatEditingSessionStream, token: CancellationToken) => Promise, options?: { silent?: boolean }): Promise { - const session = this._currentSessionObs.get(); - if (!session) { - throw new BugIndicatingError('Cannot continue missing session'); - } - + private async _continueEditingSession(session: ChatEditingSession, builder: (stream: IChatEditingSessionStream, token: CancellationToken) => Promise): Promise { if (session.state.get() === ChatEditingSessionState.StreamingEdits) { throw new BugIndicatingError('Cannot continue session that is still streaming'); } - let editorPane: MultiDiffEditor | undefined; - if (!options?.silent && session.isVisible) { - const groupedEditors = this._findGroupedEditors(); - if (groupedEditors.length !== 1) { - throw new Error(`Unexpected number of editors: ${groupedEditors.length}`); - } - const [group, editor] = groupedEditors[0]; - - editorPane = await group.openEditor(editor, { pinned: true, activation: EditorActivation.ACTIVATE }) as MultiDiffEditor | undefined; - } - const stream: IChatEditingSessionStream = { textEdits: (resource: URI, textEdits: TextEdit[], isDone: boolean, responseModel: IChatResponseModel) => { session.acceptTextEdits(resource, textEdits, isDone, responseModel); @@ -368,18 +349,15 @@ export class ChatEditingService extends Disposable implements IChatEditingServic const cancellationTokenSource = new CancellationTokenSource(); this._currentAutoApplyOperationObs.set(cancellationTokenSource, undefined); try { - if (editorPane) { - await editorPane?.showWhile(builder(stream, cancellationTokenSource.token)); - } else { - await this._progressService.withProgress({ - location: ProgressLocation.Window, - title: localize2('chatEditing.startingSession', 'Generating edits...').value, - }, async () => { - await builder(stream, cancellationTokenSource.token); - }, - () => cancellationTokenSource.cancel() - ); - } + await this._progressService.withProgress({ + location: ProgressLocation.Window, + title: localize2('chatEditing.startingSession', 'Generating edits...').value, + }, async () => { + await builder(stream, cancellationTokenSource.token); + }, + () => cancellationTokenSource.cancel() + ); + } finally { cancellationTokenSource.dispose(); this._currentAutoApplyOperationObs.set(null, undefined); @@ -387,18 +365,6 @@ export class ChatEditingService extends Disposable implements IChatEditingServic } } - private _findGroupedEditors() { - const editors: [IEditorGroup, EditorInput][] = []; - for (const group of this._editorGroupsService.groups) { - for (const editor of group.editors) { - if (editor.resource?.scheme === ChatEditingMultiDiffSourceResolver.scheme) { - editors.push([group, editor]); - } - } - } - return editors; - } - hasRelatedFilesProviders(): boolean { return this._chatRelatedFilesProviders.size > 0; } diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 3b0aaa58dc859..316f2a724d6bd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -889,11 +889,6 @@ export class ChatWidget extends Disposable implements IChatWidget { if (e.kind === 'setAgent') { this._onDidChangeAgent.fire({ agent: e.agent, slashCommand: e.command }); } - if (e.kind === 'addRequest') { - if (this._location.location === ChatAgentLocation.EditingSession) { - this.chatEditingService.createSnapshot(e.request.id); - } - } })); if (this.tree && this.visible) {