diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index fcb5d2ec4e4..568a0124c12 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -777,6 +777,16 @@ export class DisposableMap implements ID this._store.delete(key); } + /** + * Delete the value stored for `key` from this map but return it. The caller is + * responsible for disposing of the value. + */ + deleteAndLeak(key: K): V | undefined { + const value = this._store.get(key); + this._store.delete(key); + return value; + } + keys(): IterableIterator { return this._store.keys(); } diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 500af3ab715..7338d036535 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -20,7 +20,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ILogService } from 'vs/platform/log/common/log'; import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService, reviveSerializedAgent } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestTextPart, IParsedChatRequest, getPromptText, reviveParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; -import { IChatAgentMarkdownContentWithVulnerability, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgress, IChatProgressMessage, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatTreeData, IChatUsedContext, IChatWarningMessage, ChatAgentVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatAgentMarkdownContentWithVulnerability, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgressMessage, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatTreeData, IChatUsedContext, IChatWarningMessage, ChatAgentVoteDirection, isIUsedContext, IChatProgress } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables'; export interface IChatRequestVariableEntry { @@ -109,9 +109,10 @@ export class ChatRequestModel implements IChatRequestModel { public response: ChatResponseModel | undefined; - private _id: string; - public get id(): string { - return this._id; + public readonly id: string; + + public get session() { + return this._session; } public get username(): string { @@ -135,12 +136,16 @@ export class ChatRequestModel implements IChatRequestModel { } constructor( - public readonly session: ChatModel, + private _session: ChatModel, public readonly message: IParsedChatRequest, private _variableData: IChatRequestVariableData, private _attempt: number = 0 ) { - this._id = 'request_' + ChatRequestModel.nextId++; + this.id = 'request_' + ChatRequestModel.nextId++; + } + + adoptTo(session: ChatModel) { + this._session = session; } } @@ -267,9 +272,10 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel private static nextId = 0; - private _id: string; - public get id(): string { - return this._id; + public readonly id: string; + + public get session() { + return this._session; } public get isComplete(): boolean { @@ -342,7 +348,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel constructor( _response: IMarkdownString | ReadonlyArray, - public readonly session: ChatModel, + private _session: ChatModel, private _agent: IChatAgentData | undefined, private _slashCommand: IChatAgentCommand | undefined, public readonly requestId: string, @@ -360,7 +366,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel this._followups = followups ? [...followups] : undefined; this._response = new Response(_response); this._register(this._response.onDidChangeValue(() => this._onDidChange.fire())); - this._id = 'response_' + ChatResponseModel.nextId++; + this.id = 'response_' + ChatResponseModel.nextId++; } /** @@ -430,6 +436,11 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel this._onDidChange.fire(); return true; } + + adoptTo(session: ChatModel) { + this._session = session; + this._onDidChange.fire(); + } } export interface IChatModel { @@ -773,6 +784,26 @@ export class ChatModel extends Disposable implements IChatModel { return request; } + adoptRequest(request: ChatRequestModel): void { + + // this doesn't use `removeRequest` because it must not dispose the request object + const oldOwner = request.session; + const index = oldOwner._requests.findIndex(candidate => candidate.id === request.id); + + if (index === -1) { + return; + } + + oldOwner._requests.splice(index, 1); + + request.adoptTo(this); + request.response?.adoptTo(this); + this._requests.push(request); + + oldOwner._onDidChange.fire({ kind: 'removeRequest', requestId: request.id, responseId: request.response?.id }); + this._onDidChange.fire({ kind: 'addRequest', request }); + } + acceptResponseProgress(request: ChatRequestModel, progress: IChatProgress, quiet?: boolean): void { if (!request.response) { request.response = new ChatResponseModel([], this, undefined, undefined, request.id); diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index f83ae8990a0..a6921314d18 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -331,7 +331,7 @@ export interface IChatService { sendRequest(sessionId: string, message: string, options?: IChatSendRequestOptions): Promise; resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions): Promise; - + adoptRequest(sessionId: string, request: IChatRequestModel): Promise; removeRequest(sessionid: string, requestId: string): Promise; cancelCurrentRequestForSession(sessionId: string): void; clearSession(sessionId: string): void; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 4b093e11637..5ac341490c9 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -700,6 +700,28 @@ export class ChatService extends Disposable implements IChatService { model.removeRequest(requestId); } + async adoptRequest(sessionId: string, request: IChatRequestModel) { + if (!(request instanceof ChatRequestModel)) { + throw new TypeError('Can only adopt requests of type ChatRequestModel'); + } + const target = this._sessionModels.get(sessionId); + if (!target) { + throw new Error(`Unknown session: ${sessionId}`); + } + + await target.waitForInitialization(); + + const oldOwner = request.session; + target.adoptRequest(request); + + if (request.response && !request.response.isComplete) { + const cts = this._pendingRequests.deleteAndLeak(oldOwner.sessionId); + if (cts) { + this._pendingRequests.set(target.sessionId, cts); + } + } + } + async addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, attempt: number | undefined, response: IChatCompleteResponse): Promise { this.trace('addCompleteRequest', `message: ${message}`); diff --git a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts index f611d83b246..b9f38a04549 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts @@ -121,6 +121,36 @@ suite('ChatModel', () => { model.removeRequest(requests[0].id); assert.strictEqual(model.getRequests().length, 0); }); + + test('adoptRequest', async function () { + const model1 = testDisposables.add(instantiationService.createInstance(ChatModel, undefined, ChatAgentLocation.Editor)); + const model2 = testDisposables.add(instantiationService.createInstance(ChatModel, undefined, ChatAgentLocation.Panel)); + + model1.startInitialize(); + model1.initialize(undefined); + + model2.startInitialize(); + model2.initialize(undefined); + + const text = 'hello'; + const request1 = model1.addRequest({ text, parts: [new ChatRequestTextPart(new OffsetRange(0, text.length), new Range(1, text.length, 1, text.length), text)] }, { variables: [] }, 0); + + assert.strictEqual(model1.getRequests().length, 1); + assert.strictEqual(model2.getRequests().length, 0); + assert.ok(request1.session === model1); + assert.ok(request1.response?.session === model1); + + model2.adoptRequest(request1); + + assert.strictEqual(model1.getRequests().length, 0); + assert.strictEqual(model2.getRequests().length, 1); + assert.ok(request1.session === model2); + assert.ok(request1.response?.session === model2); + + model2.acceptResponseProgress(request1, { content: new MarkdownString('Hello'), kind: 'markdownContent' }); + + assert.strictEqual(request1.response.response.asString(), 'Hello'); + }); }); suite('Response', () => { diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatService.ts b/src/vs/workbench/contrib/chat/test/common/mockChatService.ts index f2671c73f59..c7cc9199757 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatService.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatService.ts @@ -46,6 +46,9 @@ export class MockChatService implements IChatService { resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions | undefined): Promise { throw new Error('Method not implemented.'); } + adoptRequest(sessionId: string, request: IChatRequestModel): Promise { + throw new Error('Method not implemented.'); + } removeRequest(sessionid: string, requestId: string): Promise { throw new Error('Method not implemented.'); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 472bd45cf46..ce5b514ede3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -29,6 +29,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { ILogService } from 'vs/platform/log/common/log'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; +import { CONTEXT_CHAT_REQUEST_IN_PROGRESS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; CommandsRegistry.registerCommandAlias('interactiveEditor.start', 'inlineChat.start'); CommandsRegistry.registerCommandAlias('interactive.acceptChanges', ACTION_ACCEPT_CHANGES); @@ -482,15 +483,14 @@ export class ViewInChatAction extends AbstractInlineChatAction { icon: Codicon.commentDiscussion, precondition: CTX_INLINE_CHAT_VISIBLE, menu: { - id: MENU_INLINE_CHAT_WIDGET_STATUS, - when: CTX_INLINE_CHAT_RESPONSE_TYPES.isEqualTo(InlineChatResponseTypes.OnlyMessages), - group: '0_main', - order: 1 + id: MENU_INLINE_CHAT_WIDGET, + group: 'navigation', + order: 5 } }); } - override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]): void { - ctrl.viewInChat(); + override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]) { + return ctrl.viewInChat(); } } @@ -501,6 +501,7 @@ export class RerunAction extends AbstractInlineChatAction { title: localize2('chat.rerun.label', "Rerun Request"), f1: false, icon: Codicon.refresh, + precondition: CONTEXT_CHAT_REQUEST_IN_PROGRESS.negate(), menu: { id: MENU_INLINE_CHAT_WIDGET_STATUS, group: '0_main', diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index bac8e7419f3..98a8f4294a5 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -29,8 +29,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IChatWidgetService, showChatView } from 'vs/workbench/contrib/chat/browser/chat'; -import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; -import { chatAgentLeader, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IInlineChatSavingService } from './inlineChatSavingService'; import { EmptyResponse, ErrorResponse, ReplyResponse, Session, SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; @@ -42,12 +40,10 @@ import { StashedSession } from './inlineChatSession'; import { IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model'; import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatContentWidget'; import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; -import { tail } from 'vs/base/common/arrays'; -import { IChatRequestModel, IResponse } from 'vs/workbench/contrib/chat/common/chatModel'; +import { ChatModel, IChatRequestModel, IResponse } from 'vs/workbench/contrib/chat/common/chatModel'; import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart'; -import { OffsetRange } from 'vs/editor/common/core/offsetRange'; import { isEqual } from 'vs/base/common/resources'; import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; @@ -144,7 +140,6 @@ export class InlineChatController implements IEditorContribution { @IConfigurationService private readonly _configurationService: IConfigurationService, @IDialogService private readonly _dialogService: IDialogService, @IContextKeyService contextKeyService: IContextKeyService, - @IChatAgentService private readonly _chatAgentService: IChatAgentService, @IChatService private readonly _chatService: IChatService, @ILanguageFeaturesService private readonly _languageFeatureService: ILanguageFeaturesService, @IChatWidgetService private readonly _chatWidgetService: IChatWidgetService, @@ -428,14 +423,14 @@ export class InlineChatController implements IEditorContribution { }); } else if (e.kind === 'removeRequest') { // TODO@jrieken this currently is buggy when removing not the very last request/response - if (this._session!.lastExchange?.response instanceof ReplyResponse) { - try { - this._session!.hunkData.ignoreTextModelNChanges = true; - await this._strategy!.undoChanges(this._session!.lastExchange.response.modelAltVersionId); - } finally { - this._session!.hunkData.ignoreTextModelNChanges = false; - } - } + // if (this._session!.lastExchange?.response instanceof ReplyResponse) { + // try { + // this._session!.hunkData.ignoreTextModelNChanges = true; + // await this._strategy!.undoChanges(this._session!.lastExchange.response.modelAltVersionId); + // } finally { + // this._session!.hunkData.ignoreTextModelNChanges = false; + // } + // } } })); @@ -468,7 +463,6 @@ export class InlineChatController implements IEditorContribution { kind: CompletionItemKind.Text, insertText: withSlash, range: Range.fromPositions(new Position(1, 1), position), - command: command.executeImmediately ? { id: 'workbench.action.chat.acceptInput', title: withSlash } : undefined }); } @@ -599,55 +593,18 @@ export class InlineChatController implements IEditorContribution { const input = request.message.text; this._zone.value.widget.value = input; - // slash command referring - let slashCommandLike = request.message.parts.find(part => part instanceof ChatRequestAgentSubcommandPart || part instanceof ChatRequestSlashCommandPart); - const refer = this._session.session.slashCommands?.some(value => { - if (value.refer) { - if (slashCommandLike?.text === `/${value.command}`) { - return true; - } - if (request?.message.text.startsWith(`/${value.command}`)) { - slashCommandLike = new ChatRequestSlashCommandPart(new OffsetRange(0, 1), new Range(1, 1, 1, 1), { command: value.command, detail: value.detail ?? '' }); - return true; - } - } - return false; - }); - if (refer && slashCommandLike && !this._session.lastExchange) { - this._log('[IE] seeing refer command, continuing outside editor', this._session.agent.extensionId); - - // cancel this request - this._chatService.cancelCurrentRequestForSession(request.session.sessionId); - - this._editor.setSelection(this._session.wholeRange.value); - let massagedInput = input; - const withoutSubCommandLeader = slashCommandLike.text.slice(1); - for (const agent of this._chatAgentService.getActivatedAgents()) { - if (agent.locations.includes(ChatAgentLocation.Panel)) { - const commands = agent.slashCommands; - if (commands.find((command) => withoutSubCommandLeader.startsWith(command.name))) { - massagedInput = `${chatAgentLeader}${agent.name} ${slashCommandLike.text}`; - break; - } - } - } - // if agent has a refer command, massage the input to include the agent name - await this._instaService.invokeFunction(sendRequest, massagedInput); - - return State.ACCEPT; - } - this._session.addInput(new SessionPrompt(request)); return State.SHOW_REQUEST; } - private async [State.SHOW_REQUEST](): Promise { + private async [State.SHOW_REQUEST](): Promise { assertType(this._session); assertType(this._session.chatModel.requestInProgress); - const request: IChatRequestModel | undefined = tail(this._session.chatModel.getRequests()); + const { chatModel } = this._session; + const request: IChatRequestModel | undefined = chatModel.getRequests().at(-1); assertType(request); assertType(request.response); @@ -667,18 +624,30 @@ export class InlineChatController implements IEditorContribution { const progressiveEditsClock = StopWatch.create(); const progressiveEditsQueue = new Queue(); + let next: State.SHOW_RESPONSE | State.CANCEL | State.PAUSE | State.ACCEPT | State.WAIT_FOR_INPUT = State.SHOW_RESPONSE; + store.add(Event.once(this._messages.event)(message => { + this._log('state=_makeRequest) message received', message); + this._chatService.cancelCurrentRequestForSession(chatModel.sessionId); + if (message & Message.CANCEL_SESSION) { + next = State.CANCEL; + } else if (message & Message.PAUSE_SESSION) { + next = State.PAUSE; + } else if (message & Message.ACCEPT_SESSION) { + next = State.ACCEPT; + } + })); - - let message = Message.NONE; - store.add(Event.once(this._messages.event)(m => { - this._log('state=_makeRequest) message received', m); - this._chatService.cancelCurrentRequestForSession(request.session.sessionId); - message = m; + store.add(chatModel.onDidChange(e => { + if (e.kind === 'removeRequest' && e.requestId === request.id) { + progressiveEditsCts.cancel(); + responsePromise.complete(); + next = State.CANCEL; + } })); // cancel the request when the user types store.add(this._zone.value.widget.chatWidget.inputEditor.onDidChangeModelContent(() => { - this._chatService.cancelCurrentRequestForSession(request.session.sessionId); + this._chatService.cancelCurrentRequestForSession(chatModel.sessionId); })); let lastLength = 0; @@ -754,16 +723,9 @@ export class InlineChatController implements IEditorContribution { await this._session.hunkData.recompute(); this._zone.value.widget.updateToolbar(true); + this._zone.value.widget.updateProgress(false); - if (message & Message.CANCEL_SESSION) { - return State.CANCEL; - } else if (message & Message.PAUSE_SESSION) { - return State.PAUSE; - } else if (message & Message.ACCEPT_SESSION) { - return State.ACCEPT; - } else { - return State.SHOW_RESPONSE; - } + return next; } private async[State.SHOW_RESPONSE](): Promise { @@ -1040,11 +1002,21 @@ export class InlineChatController implements IEditorContribution { this._strategy?.move?.(next); } - - viewInChat() { - if (this._session?.lastExchange?.response instanceof ReplyResponse) { - this._instaService.invokeFunction(showMessageResponse, this._session.lastExchange.prompt.value, this._session.lastExchange.response.mdContent.value); + async viewInChat() { + if (!this._strategy || !this._session) { + return; } + + // TODO@jrieken REMOVE this as soon as we can mark responses as accepted + // and as soon as hunks support request-linking + const textEditsResponseCount = this._session.chatModel.getRequests().filter(request => request.response?.response.value.some(part => part.kind === 'textEditGroup')).length; + if (textEditsResponseCount > 1) { + return; + } + + this._strategy.cancel(); + await this._instaService.invokeFunction(moveToPanelChat, this._session?.chatModel); + this.cancelSession(); } toggleDiff() { @@ -1061,7 +1033,7 @@ export class InlineChatController implements IEditorContribution { if (this._session?.lastExchange?.response instanceof ReplyResponse && this._session?.lastExchange?.response.chatResponse) { const response = this._session?.lastExchange?.response.chatResponse; this._chatService.notifyUserAction({ - sessionId: response.session.sessionId, + sessionId: this._session.chatModel.sessionId, requestId: response.requestId, agentId: response.agent?.id, result: response.result, @@ -1093,7 +1065,7 @@ export class InlineChatController implements IEditorContribution { if (this._session.lastExchange?.response instanceof ReplyResponse && this._session?.lastExchange?.response.chatResponse) { const response = this._session?.lastExchange?.response.chatResponse; this._chatService.notifyUserAction({ - sessionId: response.session.sessionId, + sessionId: this._session.chatModel.sessionId, requestId: response.requestId, agentId: response.agent?.id, result: response.result, @@ -1134,35 +1106,21 @@ export class InlineChatController implements IEditorContribution { } } -async function showMessageResponse(accessor: ServicesAccessor, query: string, response: string) { - const chatService = accessor.get(IChatService); - const chatAgentService = accessor.get(IChatAgentService); - const agent = chatAgentService.getActivatedAgents().find(agent => agent.locations.includes(ChatAgentLocation.Panel) && agent.isDefault); - if (!agent) { - return; - } +async function moveToPanelChat(accessor: ServicesAccessor, model: ChatModel | undefined) { - const widget = await showChatView(accessor.get(IViewsService)); - if (widget && widget.viewModel) { - chatService.addCompleteRequest(widget.viewModel.sessionId, query, undefined, 0, { message: response }); + const viewsService = accessor.get(IViewsService); + const chatService = accessor.get(IChatService); + + const widget = await showChatView(viewsService); + + if (widget && widget.viewModel && model) { + for (const request of model.getRequests().slice()) { + await chatService.adoptRequest(widget.viewModel.model.sessionId, request); + } widget.focusLastMessage(); } } -async function sendRequest(accessor: ServicesAccessor, query: string) { - const chatAgentService = accessor.get(IChatAgentService); - const agent = chatAgentService.getActivatedAgents().find(agent => agent.locations.includes(ChatAgentLocation.Panel) && agent.isDefault); - if (!agent) { - return; - } - const widget = await showChatView(accessor.get(IViewsService)); - if (!widget) { - return; - } - widget.focusInput(); - widget.acceptInput(query); -} - function asInlineChatResponseType(response: IResponse): InlineChatResponseTypes { let result: InlineChatResponseTypes | undefined; for (const item of response.value) { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index 7e77096a55c..36741784114 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -154,7 +154,6 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { return { command: agentCommand.name, detail: agentCommand.description, - refer: agentCommand.name === 'explain' // TODO@jrieken @joyceerhl this should be cleaned up } satisfies IInlineChatSlashCommand; }) }; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 2f1e2e33266..458c0da69a6 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -17,7 +17,7 @@ import { LineRange } from 'vs/editor/common/core/lineRange'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon'; -import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel, IValidEditOperation, MinimapPosition, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, IValidEditOperation, MinimapPosition, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel'; @@ -136,8 +136,6 @@ export abstract class EditModeStrategy { abstract makeChanges(edits: ISingleEditOperation[], obs: IEditObserver, undoStopBefore: boolean): Promise; - abstract undoChanges(altVersionId: number): Promise; - abstract renderChanges(response: ReplyResponse): Promise; move?(next: boolean): void; @@ -192,14 +190,7 @@ export class PreviewStrategy extends EditModeStrategy { override async makeProgressiveChanges(): Promise { } - override async undoChanges(altVersionId: number): Promise { - const { textModelN } = this._session; - await undoModelUntil(textModelN, altVersionId); - } - - override async renderChanges(response: ReplyResponse): Promise { - - } + override async renderChanges(response: ReplyResponse): Promise { } hasFocus(): boolean { return this._zone.widget.hasFocus(); @@ -313,11 +304,6 @@ export class LiveStrategy extends EditModeStrategy { return super.cancel(); } - override async undoChanges(altVersionId: number): Promise { - const { textModelN } = this._session; - await undoModelUntil(textModelN, altVersionId); - } - override async makeChanges(edits: ISingleEditOperation[], obs: IEditObserver, undoStopBefore: boolean): Promise { return this._makeChanges(edits, obs, undefined, undefined, undoStopBefore); } @@ -618,14 +604,6 @@ export class LiveStrategy extends EditModeStrategy { } } - -async function undoModelUntil(model: ITextModel, targetAltVersion: number): Promise { - while (targetAltVersion < model.getAlternativeVersionId() && model.canUndo()) { - await model.undo(); - } -} - - function changeDecorationsAndViewZones(editor: ICodeEditor, callback: (accessor: IModelDecorationsChangeAccessor, viewZoneAccessor: IViewZoneChangeAccessor) => void): void { editor.changeDecorations(decorationsAccessor => { editor.changeViewZones(viewZoneAccessor => { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts index d37ea30b024..5dcca5cbb31 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts @@ -14,7 +14,7 @@ import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, EditMode, InlineChatConfigKeys, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, EditMode, InlineChatConfigKeys, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { EditorBasedInlineChatWidget } from './inlineChatWidget'; import { MenuId } from 'vs/platform/actions/common/actions'; import { isEqual } from 'vs/base/common/resources'; @@ -53,9 +53,9 @@ export class InlineChatZoneWidget extends ZoneWidget { menu: MENU_INLINE_CHAT_WIDGET_STATUS, options: { buttonConfigProvider: action => { - if (action.id === ACTION_REGENERATE_RESPONSE || action.id === ACTION_TOGGLE_DIFF) { - return { showIcon: true, showLabel: false, isSecondary: true }; - } else if (action.id === ACTION_VIEW_IN_CHAT || action.id === ACTION_ACCEPT_CHANGES) { + if (new Set([ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF]).has(action.id)) { + return { isSecondary: true, showIcon: true, showLabel: false }; + } else if (action.id === ACTION_ACCEPT_CHANGES) { return { isSecondary: false }; } else { return { isSecondary: true }; diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 37beed15c3a..2ee3979e13d 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -23,8 +23,6 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export interface IInlineChatSlashCommand { command: string; detail?: string; - refer?: boolean; - executeImmediately?: boolean; } export interface IInlineChatSession {