Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.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 * as dom from '../../../../../base/browser/dom.js';
7
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
8
import { localize2 } from '../../../../../nls.js';
9
import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';
10
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
11
import { CHAT_CATEGORY, stringifyItem } from './chatActions.js';
12
import { ChatTreeItem, IChatWidgetService } from '../chat.js';
13
import { ChatContextKeys } from '../../common/chatContextKeys.js';
14
import { IChatRequestViewModel, IChatResponseViewModel, isChatTreeItem, isRequestVM, isResponseVM } from '../../common/chatViewModel.js';
15
16
export function registerChatCopyActions() {
17
registerAction2(class CopyAllAction extends Action2 {
18
constructor() {
19
super({
20
id: 'workbench.action.chat.copyAll',
21
title: localize2('interactive.copyAll.label', "Copy All"),
22
f1: false,
23
category: CHAT_CATEGORY,
24
menu: {
25
id: MenuId.ChatContext,
26
when: ChatContextKeys.responseIsFiltered.negate(),
27
group: 'copy',
28
}
29
});
30
}
31
32
run(accessor: ServicesAccessor, ...args: any[]) {
33
const clipboardService = accessor.get(IClipboardService);
34
const chatWidgetService = accessor.get(IChatWidgetService);
35
const widget = chatWidgetService.lastFocusedWidget;
36
if (widget) {
37
const viewModel = widget.viewModel;
38
const sessionAsText = viewModel?.getItems()
39
.filter((item): item is (IChatRequestViewModel | IChatResponseViewModel) => isRequestVM(item) || (isResponseVM(item) && !item.errorDetails?.responseIsFiltered))
40
.map(item => stringifyItem(item))
41
.join('\n\n');
42
if (sessionAsText) {
43
clipboardService.writeText(sessionAsText);
44
}
45
}
46
}
47
});
48
49
registerAction2(class CopyItemAction extends Action2 {
50
constructor() {
51
super({
52
id: 'workbench.action.chat.copyItem',
53
title: localize2('interactive.copyItem.label', "Copy"),
54
f1: false,
55
category: CHAT_CATEGORY,
56
menu: {
57
id: MenuId.ChatContext,
58
when: ChatContextKeys.responseIsFiltered.negate(),
59
group: 'copy',
60
}
61
});
62
}
63
64
async run(accessor: ServicesAccessor, ...args: any[]) {
65
const chatWidgetService = accessor.get(IChatWidgetService);
66
const clipboardService = accessor.get(IClipboardService);
67
68
const widget = chatWidgetService.lastFocusedWidget;
69
let item: ChatTreeItem | undefined = args[0];
70
if (!isChatTreeItem(item)) {
71
item = widget?.getFocus();
72
if (!item) {
73
return;
74
}
75
}
76
77
// If there is a text selection, and focus is inside the widget, copy the selected text.
78
// Otherwise, context menu with no selection -> copy the full item
79
const nativeSelection = dom.getActiveWindow().getSelection();
80
const selectedText = nativeSelection?.toString();
81
if (widget && selectedText && selectedText.length > 0 && dom.isAncestor(dom.getActiveElement(), widget.domNode)) {
82
await clipboardService.writeText(selectedText);
83
return;
84
}
85
86
const text = stringifyItem(item, false);
87
await clipboardService.writeText(text);
88
}
89
});
90
}
91
92