Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts
5310 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 { ThemeIcon } from '../../../../../base/common/themables.js';
8
import { URI } from '../../../../../base/common/uri.js';
9
import { localize, localize2 } from '../../../../../nls.js';
10
import { Action2, MenuId, MenuRegistry, registerAction2 } from '../../../../../platform/actions/common/actions.js';
11
import { ContextKeyExpr, ContextKeyExpression } from '../../../../../platform/contextkey/common/contextkey.js';
12
import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';
13
import { ActiveEditorContext } from '../../../../common/contextkeys.js';
14
import { ViewContainerLocation } from '../../../../common/views.js';
15
import { IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js';
16
import { ACTIVE_GROUP, AUX_WINDOW_GROUP, IEditorService } from '../../../../services/editor/common/editorService.js';
17
import { IViewsService } from '../../../../services/views/common/viewsService.js';
18
import { isChatViewTitleActionContext } from '../../common/actions/chatActions.js';
19
import { ChatContextKeys } from '../../common/actions/chatContextKeys.js';
20
import { ChatAgentLocation } from '../../common/constants.js';
21
import { ChatViewId, IChatWidgetService } from '../chat.js';
22
import { ChatEditor, IChatEditorOptions } from '../widgetHosts/editor/chatEditor.js';
23
import { ChatEditorInput } from '../widgetHosts/editor/chatEditorInput.js';
24
import { ChatViewPane } from '../widgetHosts/viewPane/chatViewPane.js';
25
import { CHAT_CATEGORY } from './chatActions.js';
26
27
enum MoveToNewLocation {
28
Editor = 'Editor',
29
Window = 'Window'
30
}
31
32
export function registerMoveActions() {
33
registerAction2(class GlobalMoveToEditorAction extends Action2 {
34
constructor() {
35
super({
36
id: 'workbench.action.chat.openInEditor',
37
title: localize2('chat.openInEditor.label', "Move Chat into Editor Area"),
38
category: CHAT_CATEGORY,
39
precondition: ChatContextKeys.enabled,
40
f1: true,
41
menu: {
42
id: MenuId.ViewTitle,
43
when: ContextKeyExpr.equals('view', ChatViewId),
44
order: 0,
45
group: '1_open'
46
},
47
});
48
}
49
50
async run(accessor: ServicesAccessor, ...args: unknown[]) {
51
const context = args[0];
52
executeMoveToAction(accessor, MoveToNewLocation.Editor, isChatViewTitleActionContext(context) ? context.sessionResource : undefined);
53
}
54
});
55
56
registerAction2(class GlobalMoveToNewWindowAction extends Action2 {
57
constructor() {
58
super({
59
id: 'workbench.action.chat.openInNewWindow',
60
title: localize2('chat.openInNewWindow.label', "Move Chat into New Window"),
61
category: CHAT_CATEGORY,
62
precondition: ChatContextKeys.enabled,
63
f1: true,
64
menu: {
65
id: MenuId.ViewTitle,
66
when: ContextKeyExpr.equals('view', ChatViewId),
67
order: 0,
68
group: '1_open'
69
},
70
});
71
}
72
73
async run(accessor: ServicesAccessor, ...args: unknown[]) {
74
const context = args[0];
75
executeMoveToAction(accessor, MoveToNewLocation.Window, isChatViewTitleActionContext(context) ? context.sessionResource : undefined);
76
}
77
});
78
79
registerAction2(class GlobalMoveToSidebarAction extends Action2 {
80
constructor() {
81
super({
82
id: 'workbench.action.chat.openInSidebar',
83
title: localize2('interactiveSession.openInSidebar.label', "Move Chat into Side Bar"),
84
category: CHAT_CATEGORY,
85
precondition: ChatContextKeys.enabled,
86
f1: true
87
});
88
}
89
90
async run(accessor: ServicesAccessor, ...args: unknown[]) {
91
return moveToSidebar(accessor);
92
}
93
});
94
95
function appendOpenChatInViewMenuItem(menuId: MenuId, title: string, icon: ThemeIcon, locationContextKey: ContextKeyExpression) {
96
MenuRegistry.appendMenuItem(menuId, {
97
command: { id: 'workbench.action.chat.openInSidebar', title, icon },
98
when: ContextKeyExpr.and(
99
ActiveEditorContext.isEqualTo(ChatEditorInput.EditorID),
100
locationContextKey
101
),
102
group: menuId === MenuId.CompactWindowEditorTitle ? 'navigation' : undefined,
103
order: 0
104
});
105
}
106
107
[MenuId.EditorTitle, MenuId.CompactWindowEditorTitle].forEach(id => {
108
appendOpenChatInViewMenuItem(id, localize('interactiveSession.openInSecondarySidebar.label', "Move Chat into Secondary Side Bar"), Codicon.layoutSidebarRightDock, ChatContextKeys.panelLocation.isEqualTo(ViewContainerLocation.AuxiliaryBar));
109
appendOpenChatInViewMenuItem(id, localize('interactiveSession.openInPrimarySidebar.label', "Move Chat into Primary Side Bar"), Codicon.layoutSidebarLeftDock, ChatContextKeys.panelLocation.isEqualTo(ViewContainerLocation.Sidebar));
110
appendOpenChatInViewMenuItem(id, localize('interactiveSession.openInPanel.label', "Move Chat into Panel"), Codicon.layoutPanelDock, ChatContextKeys.panelLocation.isEqualTo(ViewContainerLocation.Panel));
111
});
112
}
113
114
async function executeMoveToAction(accessor: ServicesAccessor, moveTo: MoveToNewLocation, sessionResource?: URI) {
115
const widgetService = accessor.get(IChatWidgetService);
116
117
const auxiliary = { compact: true, bounds: { width: 800, height: 640 } };
118
119
const widget = (sessionResource ? widgetService.getWidgetBySessionResource(sessionResource) : undefined)
120
?? widgetService.lastFocusedWidget;
121
if (!widget || !widget.viewModel || widget.location !== ChatAgentLocation.Chat) {
122
await widgetService.openSession(ChatEditorInput.getNewEditorUri(), moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP, { pinned: true, auxiliary });
123
return;
124
}
125
126
const existingWidget = widgetService.getWidgetBySessionResource(widget.viewModel.sessionResource);
127
if (!existingWidget) {
128
// Do NOT attempt to open a session that isn't already open since we cannot guarantee its state.
129
await widgetService.openSession(ChatEditorInput.getNewEditorUri(), moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP, { pinned: true, auxiliary });
130
return;
131
}
132
133
// Save off the session resource before clearing
134
const resourceToOpen = widget.viewModel.sessionResource;
135
136
// Todo: can possibly go away with https://github.com/microsoft/vscode/pull/278476
137
const modelInputState = existingWidget.getViewState();
138
139
await widget.clear();
140
141
const options: IChatEditorOptions = { pinned: true, modelInputState, auxiliary };
142
await widgetService.openSession(resourceToOpen, moveTo === MoveToNewLocation.Window ? AUX_WINDOW_GROUP : ACTIVE_GROUP, options);
143
}
144
145
async function moveToSidebar(accessor: ServicesAccessor): Promise<void> {
146
const viewsService = accessor.get(IViewsService);
147
const editorService = accessor.get(IEditorService);
148
const editorGroupService = accessor.get(IEditorGroupsService);
149
150
const chatEditor = editorService.activeEditorPane;
151
const chatEditorInput = chatEditor?.input;
152
let view: ChatViewPane;
153
if (chatEditor instanceof ChatEditor && chatEditorInput instanceof ChatEditorInput && chatEditorInput.sessionResource) {
154
const previousViewState = chatEditor.widget.getViewState();
155
await editorService.closeEditor({ editor: chatEditor.input, groupId: editorGroupService.activeGroup.id });
156
view = await viewsService.openView(ChatViewId) as ChatViewPane;
157
158
// Todo: can possibly go away with https://github.com/microsoft/vscode/pull/278476
159
const newModel = await view.loadSession(chatEditorInput.sessionResource);
160
if (previousViewState && newModel && !newModel.inputModel.state.get()) {
161
newModel.inputModel.setState(previousViewState);
162
}
163
} else {
164
view = await viewsService.openView(ChatViewId) as ChatViewPane;
165
}
166
167
view.focus();
168
}
169
170