Skip to content

Commit

Permalink
Add copy actions to interactive session list (#176685)
Browse files Browse the repository at this point in the history
* Add Copy/Copy All actions to interactive sessions

* Remove Copy from F1

* Remove from command palette
  • Loading branch information
roblourens committed Mar 10, 2023
1 parent fc12c7e commit ef1542d
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export class MenuId {
static readonly MergeBaseToolbar = new MenuId('MergeBaseToolbar');
static readonly MergeInputResultToolbar = new MenuId('MergeToolbarResultToolbar');
static readonly InlineSuggestionToolbar = new MenuId('InlineSuggestionToolbar');
static readonly InteractiveSessionContext = new MenuId('InteractiveSessionContext');

/**
* Create or reuse a `MenuId` with the given identifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { InteractiveSessionViewPane } from 'vs/workbench/contrib/interactiveSess
import { CONTEXT_IN_INTERACTIVE_INPUT, CONTEXT_IN_INTERACTIVE_SESSION, IInteractiveSessionWidgetService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';

const category = { value: localize('interactiveSession.category', "Interactive Session"), original: 'Interactive Session' };
export const INTERACTIVE_SESSION_CATEGORY = { value: localize('interactiveSession.category', "Interactive Session"), original: 'Interactive Session' };

export function registerInteractiveSessionActions() {
registerEditorAction(class InteractiveSessionAcceptInput extends EditorAction {
Expand Down Expand Up @@ -153,7 +153,7 @@ export function registerInteractiveSessionActions() {
value: localize('interactiveSession.clear.label', "Clear"),
original: 'Clear'
},
category,
category: INTERACTIVE_SESSION_CATEGORY,
icon: Codicon.clearAll,
f1: true
});
Expand All @@ -172,7 +172,7 @@ export function getOpenInteractiveSessionEditorAction(id: string, label: string,
id: `workbench.action.openInteractiveSession.${id}`,
title: { value: localize('interactiveSession.open', "Open Editor ({0})", label), original: `Open Editor (${label})` },
f1: true,
category,
category: INTERACTIVE_SESSION_CATEGORY,
precondition: ContextKeyExpr.deserialize(when)
});
}
Expand All @@ -197,7 +197,7 @@ const getClearInteractiveSessionActionDescriptorForViewTitle = (viewId: string,
group: 'navigation',
order: 0
},
category,
category: INTERACTIVE_SESSION_CATEGORY,
icon: Codicon.clearAll,
f1: false
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { localize } from 'vs/nls';
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { INTERACTIVE_SESSION_CATEGORY } from 'vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionActions';
import { IInteractiveSessionWidgetService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget';
import { IInteractiveRequestViewModel, IInteractiveResponseViewModel, isRequestVM, isResponseVM } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionViewModel';

export function registerInteractiveSessionCopyActions() {
registerAction2(class CopyAllAction extends Action2 {
constructor() {
super({
id: 'workbench.action.interactiveSession.copyAll',
title: {
value: localize('interactive.copyAll.label', "Copy All"),
original: 'Copy All'
},
f1: false,
category: INTERACTIVE_SESSION_CATEGORY,
menu: {
id: MenuId.InteractiveSessionContext
}
});
}

run(accessor: ServicesAccessor, ...args: any[]) {
const clipboardService = accessor.get(IClipboardService);
const interactiveWidgetService = accessor.get(IInteractiveSessionWidgetService);
const widget = interactiveWidgetService.lastFocusedWidget;
if (widget) {
const model = widget.getModel();
const sessionAsText = model?.getItems()
.map(stringifyItem)
.join('\n\n');
if (sessionAsText) {
clipboardService.writeText(sessionAsText);
}
}
}
});

registerAction2(class CopyItemAction extends Action2 {
constructor() {
super({
id: 'workbench.action.interactiveSession.copyItem',
title: {
value: localize('interactive.copyItem.label', "Copy"),
original: 'Copy'
},
f1: false,
category: INTERACTIVE_SESSION_CATEGORY,
menu: {
id: MenuId.InteractiveSessionContext
}
});
}

run(accessor: ServicesAccessor, ...args: any[]) {
const item = args[0];
if (!isRequestVM(item) && !isResponseVM(item)) {
return;
}

const clipboardService = accessor.get(IClipboardService);
const text = stringifyItem(item);
clipboardService.writeText(text);
}
});
}

function stringifyItem(item: IInteractiveRequestViewModel | IInteractiveResponseViewModel): string {
return isRequestVM(item) ?
`${item.username}: ${item.message}` : `${item.username}: ${item.response.value}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { EditorExtensions } from 'vs/workbench/common/editor';
import { registerInteractiveSessionActions } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionActions';
import { registerInteractiveSessionActions } from 'vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionActions';
import { InteractiveSessionContributionService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionContributionServiceImpl';
import { InteractiveSessionEditor } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditor';
import { InteractiveSessionEditorInput } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditorInput';
Expand All @@ -25,6 +25,7 @@ import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/s
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import '../common/interactiveSessionColors';
import { IInteractiveSessionWidgetService, InteractiveSessionWidgetService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget';
import { registerInteractiveSessionCopyActions } from 'vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionCopyActions';


// Register configuration
Expand Down Expand Up @@ -100,6 +101,7 @@ const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegist
workbenchContributionsRegistry.registerWorkbenchContribution(InteractiveSessionResolverContribution, LifecyclePhase.Starting);

registerInteractiveSessionActions();
registerInteractiveSessionCopyActions();

registerSingleton(IInteractiveSessionService, InteractiveSessionService, InstantiationType.Delayed);
registerSingleton(IInteractiveSessionContributionService, InteractiveSessionContributionService, InstantiationType.Delayed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Registry } from 'vs/platform/registry/common/platform';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation, Extensions as ViewExtensions } from 'vs/workbench/common/views';
import { getClearAction, getOpenInteractiveSessionEditorAction } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionActions';
import { getClearAction, getOpenInteractiveSessionEditorAction } from 'vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionActions';
import { IInteractiveSessionViewOptions, INTERACTIVE_SIDEBAR_PANEL_ID, InteractiveSessionViewPane } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionSidebar';
import { IInteractiveSessionContributionService, IInteractiveSessionProviderContribution, IRawInteractiveSessionProviderContribution } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionContributionService';
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import * as dom from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
Expand All @@ -22,7 +22,9 @@ import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { IModelService } from 'vs/editor/common/services/model';
import { localize } from 'vs/nls';
import { MenuId } from 'vs/platform/actions/common/actions';
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
Expand Down Expand Up @@ -104,6 +106,7 @@ export class InteractiveSessionWidget extends Disposable {
@IExtensionService private readonly extensionService: IExtensionService,
@IInteractiveSessionService private readonly interactiveSessionService: IInteractiveSessionService,
@IInteractiveSessionWidgetService interactiveSessionWidgetService: IInteractiveSessionWidgetService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
@IThemeService private readonly themeService: IThemeService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
Expand Down Expand Up @@ -246,6 +249,7 @@ export class InteractiveSessionWidget extends Disposable {
listFocusAndSelectionForeground: foreground,
}
});
this.tree.onContextMenu(e => this.onContextMenu(e));

this._register(this.tree.onDidChangeContentHeight(() => {
this.onDidChangeTreeContentHeight();
Expand All @@ -261,6 +265,19 @@ export class InteractiveSessionWidget extends Disposable {
}));
}

private onContextMenu(e: ITreeContextMenuEvent<InteractiveTreeItem | null>): void {
e.browserEvent.preventDefault();
e.browserEvent.stopPropagation();

this.contextMenuService.showContextMenu({
menuId: MenuId.InteractiveSessionContext,
menuActionOptions: { shouldForwardArgs: true },
contextKeyService: this.contextKeyService,
getAnchor: () => e.anchor,
getActionsContext: () => e.element,
});
}

private onDidChangeTreeContentHeight(): void {
if (this.tree.scrollHeight !== this.previousTreeScrollHeight) {
// Due to rounding, the scrollTop + renderHeight will not exactly match the scrollHeight.
Expand Down Expand Up @@ -444,6 +461,10 @@ export class InteractiveSessionWidget extends Disposable {
}
}

getModel(): IInteractiveSessionViewModel | undefined {
return this.viewModel;
}

layout(height: number, width: number): void {
this.bodyDimension = new dom.Dimension(width, height);
const inputHeight = Math.min(this.inputEditor.getContentHeight(), height, INPUT_EDITOR_MAX_HEIGHT);
Expand Down

0 comments on commit ef1542d

Please sign in to comment.