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