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