Path: blob/main/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Codicon } from '../../../../../base/common/codicons.js';6import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';7import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';8import { localize2 } from '../../../../../nls.js';9import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js';10import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';11import { CommandsRegistry } from '../../../../../platform/commands/common/commands.js';12import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';13import { IDialogService } from '../../../../../platform/dialogs/common/dialogs.js';14import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';15import { ActiveEditorContext } from '../../../../common/contextkeys.js';16import { ChatContextKeys } from '../../common/chatContextKeys.js';17import { IChatEditingSession } from '../../common/chatEditingService.js';18import { ChatModeKind } from '../../common/constants.js';19import { ChatViewId, IChatWidget, IChatWidgetService } from '../chat.js';20import { EditingSessionAction } from '../chatEditing/chatEditingActions.js';21import { ChatEditorInput } from '../chatEditorInput.js';22import { ACTION_ID_NEW_CHAT, ACTION_ID_NEW_EDIT_SESSION, CHAT_CATEGORY, handleCurrentEditingSession } from './chatActions.js';23import { clearChatEditor } from './chatClear.js';2425export interface INewEditSessionActionContext {26/**27* An initial prompt to write to the chat.28*/29inputValue?: string;3031/**32* Selects opening in agent mode or not. If not set, the current mode is used.33* This is ignored when coming from a chat view title context.34*/35agentMode?: boolean;3637/**38* Whether the inputValue is partial and should wait for further user input. If false or not set, the prompt is sent immediately.39*/40isPartialQuery?: boolean;41}4243export function registerNewChatActions() {44// This action was previously used for the editor gutter toolbar, but now ACTION_ID_NEW_CHAT is also used for that scenario45registerAction2(class NewChatEditorAction extends Action2 {46constructor() {47super({48id: 'workbench.action.chatEditor.newChat',49title: localize2('chat.newChat.label', "New Chat"),50icon: Codicon.plus,51f1: false,52precondition: ChatContextKeys.enabled,53});54}55async run(accessor: ServicesAccessor, ...args: any[]) {56announceChatCleared(accessor.get(IAccessibilitySignalService));57await clearChatEditor(accessor);58}59});6061registerAction2(class NewChatAction extends EditingSessionAction {62constructor() {63super({64id: ACTION_ID_NEW_CHAT,65title: localize2('chat.newEdits.label', "New Chat"),66category: CHAT_CATEGORY,67icon: Codicon.plus,68precondition: ContextKeyExpr.and(ChatContextKeys.enabled),69f1: true,70menu: [71{72id: MenuId.ChatContext,73group: 'z_clear'74},75{76id: MenuId.ViewTitle,77when: ContextKeyExpr.and(78ContextKeyExpr.equals('view', ChatViewId),79ChatContextKeys.inEmptyStateWithHistoryEnabled.negate()80),81group: 'navigation',82order: -183},84...[MenuId.EditorTitle, MenuId.CompactWindowEditorTitle].map(id => ({85id,86group: 'navigation',87when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(ChatEditorInput.EditorID), ChatContextKeys.lockedToCodingAgent.negate()),88order: 189}))90],91keybinding: {92weight: KeybindingWeight.WorkbenchContrib + 1,93primary: KeyMod.CtrlCmd | KeyCode.KeyN,94secondary: [KeyMod.CtrlCmd | KeyCode.KeyL],95mac: {96primary: KeyMod.CtrlCmd | KeyCode.KeyN,97secondary: [KeyMod.WinCtrl | KeyCode.KeyL]98},99when: ChatContextKeys.inChatSession100}101});102}103104105async runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession, widget: IChatWidget, ...args: any[]) {106const context: INewEditSessionActionContext | undefined = args[0];107const accessibilitySignalService = accessor.get(IAccessibilitySignalService);108const dialogService = accessor.get(IDialogService);109110if (!(await handleCurrentEditingSession(editingSession, undefined, dialogService))) {111return;112}113114announceChatCleared(accessibilitySignalService);115116await editingSession.stop();117widget.clear();118await widget.waitForReady();119widget.attachmentModel.clear(true);120widget.input.relatedFiles?.clear();121widget.focusInput();122123if (!context) {124return;125}126127if (typeof context.agentMode === 'boolean') {128widget.input.setChatMode(context.agentMode ? ChatModeKind.Agent : ChatModeKind.Edit);129}130131if (context.inputValue) {132if (context.isPartialQuery) {133widget.setInput(context.inputValue);134} else {135widget.acceptInput(context.inputValue);136}137}138}139});140CommandsRegistry.registerCommandAlias(ACTION_ID_NEW_EDIT_SESSION, ACTION_ID_NEW_CHAT);141142143registerAction2(class UndoChatEditInteractionAction extends EditingSessionAction {144constructor() {145super({146id: 'workbench.action.chat.undoEdit',147title: localize2('chat.undoEdit.label', "Undo Last Request"),148category: CHAT_CATEGORY,149icon: Codicon.discard,150precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanUndo, ChatContextKeys.enabled),151f1: true,152menu: [{153id: MenuId.ViewTitle,154when: ContextKeyExpr.equals('view', ChatViewId),155group: 'navigation',156order: -3,157isHiddenByDefault: true158}]159});160}161162async runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession) {163await editingSession.undoInteraction();164}165});166167registerAction2(class RedoChatEditInteractionAction extends EditingSessionAction {168constructor() {169super({170id: 'workbench.action.chat.redoEdit',171title: localize2('chat.redoEdit.label', "Redo Last Request"),172category: CHAT_CATEGORY,173icon: Codicon.redo,174precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),175f1: true,176menu: [177{178id: MenuId.ViewTitle,179when: ContextKeyExpr.equals('view', ChatViewId),180group: 'navigation',181order: -2,182isHiddenByDefault: true183}184]185});186}187188async runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession) {189const widget = accessor.get(IChatWidgetService);190await editingSession.redoInteraction();191widget.lastFocusedWidget?.viewModel?.model.setCheckpoint(undefined);192}193});194195registerAction2(class RedoChatCheckpoints extends EditingSessionAction {196constructor() {197super({198id: 'workbench.action.chat.redoEdit2',199title: localize2('chat.redoEdit.label2', "Redo"),200tooltip: localize2('chat.redoEdit.tooltip', "Reapply discarded workspace changes and chat"),201category: CHAT_CATEGORY,202precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),203f1: true,204menu: [{205id: MenuId.ChatMessageRestoreCheckpoint,206when: ChatContextKeys.lockedToCodingAgent.negate(),207group: 'navigation',208order: -1209}]210});211}212213async runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession) {214const widget = accessor.get(IChatWidgetService);215216while (editingSession.canRedo.get()) {217await editingSession.redoInteraction();218}219220const currentWidget = widget.lastFocusedWidget;221const requestText = currentWidget?.viewModel?.model.checkpoint?.message.text;222223// if the input has the same text that we just restored, clear it.224if (currentWidget?.inputEditor.getValue() === requestText) {225currentWidget?.input.setValue('', false);226}227228currentWidget?.viewModel?.model.setCheckpoint(undefined);229currentWidget?.focusInput();230}231});232}233234function announceChatCleared(accessibilitySignalService: IAccessibilitySignalService): void {235accessibilitySignalService.playSignal(AccessibilitySignal.clear);236}237238239