Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize terminal/context, terminal/title/context #192809

Merged
merged 6 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vs/base/common/marshallingIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/


export const enum MarshalledId {
Uri = 1,
Regexp,
Expand All @@ -19,6 +18,7 @@ export const enum MarshalledId {
TimelineActionContext,
NotebookCellActionContext,
NotebookActionContext,
TerminalContext,
TestItemContext,
Date,
TestMessageMenuArgs,
Expand Down
5 changes: 5 additions & 0 deletions src/vs/base/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,8 @@ export type OmitOptional<T> = { [K in keyof T as T[K] extends Required<T>[K] ? K
export type Mutable<T> = {
-readonly [P in keyof T]: T[P]
};

/**
* A single object or an array of the objects.
*/
export type SingleOrMany<T> = T | T[];
27 changes: 27 additions & 0 deletions src/vs/workbench/api/common/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { Promises } from 'vs/base/common/async';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { TerminalQuickFix, ViewColumn } from 'vs/workbench/api/common/extHostTypeConverters';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { MarshalledId } from 'vs/base/common/marshallingIds';
import { ISerializedTerminalInstanceContext } from 'vs/workbench/contrib/terminal/common/terminal';

export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {

Expand Down Expand Up @@ -416,6 +418,31 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
this._bufferer = new TerminalDataBufferer(this._proxy.$sendProcessData);
this._proxy.$registerProcessSupport(supportsProcesses);
this._extHostCommands.registerArgumentProcessor({
processArgument: arg => {
const deserialize = (arg: any) => {
const cast = arg as ISerializedTerminalInstanceContext;
return this._getTerminalById(cast.instanceId)?.value;
};
switch (arg?.$mid) {
case MarshalledId.TerminalContext: return deserialize(arg);
default: {
// Do array transformation in place as this is a hot path
if (Array.isArray(arg)) {
for (let i = 0; i < arg.length; i++) {
if (arg[i].$mid === MarshalledId.TerminalContext) {
arg[i] = deserialize(arg[i]);
} else {
// Probably something else, so exit early
break;
}
}
}
return arg;
}
}
}
});
this._register({
dispose: () => {
for (const [_, terminalProcess] of this._terminalProcesses) {
Expand Down
47 changes: 44 additions & 3 deletions src/vs/workbench/contrib/terminal/browser/terminalContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,50 @@
*--------------------------------------------------------------------------------------------*/

import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAction } from 'vs/base/common/actions';
import { ActionRunner, IAction } from 'vs/base/common/actions';
import { asArray } from 'vs/base/common/arrays';
import { MarshalledId } from 'vs/base/common/marshallingIds';
import { SingleOrMany } from 'vs/base/common/types';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ISerializedTerminalInstanceContext } from 'vs/workbench/contrib/terminal/common/terminal';

export function openContextMenu(event: MouseEvent, parent: HTMLElement, menu: IMenu, contextMenuService: IContextMenuService, extraActions?: IAction[]): void {
class InstanceContext {
private _instanceId: number;

constructor(instance: ITerminalInstance) {
this._instanceId = instance.instanceId;
}

toJSON(): ISerializedTerminalInstanceContext {
return {
$mid: MarshalledId.TerminalContext,
instanceId: this._instanceId
};
}
}

class TerminalContextActionRunner extends ActionRunner {
constructor(
private readonly _commandService: ICommandService
) {
super();
}

override run(action: IAction, context?: InstanceContext): Promise<void> {
if (Array.isArray(context) && context.every(e => e instanceof InstanceContext)) {
// arg1: The (first) focused instance
// arg2: All selected instances
return this._commandService.executeCommand(action.id, context?.[0], context);
}
return super.run(action, context);
}
}

export function openContextMenu(event: MouseEvent, contextInstances: SingleOrMany<ITerminalInstance> | undefined, menu: IMenu, commandService: ICommandService, contextMenuService: IContextMenuService, extraActions?: IAction[]): void {
const standardEvent = new StandardMouseEvent(event);

const actions: IAction[] = [];
Expand All @@ -20,9 +58,12 @@ export function openContextMenu(event: MouseEvent, parent: HTMLElement, menu: IM
actions.push(...extraActions);
}

const context: InstanceContext[] = contextInstances ? asArray(contextInstances).map(e => new InstanceContext(e)) : [];

contextMenuService.showContextMenu({
actionRunner: new TerminalContextActionRunner(commandService),
getAnchor: () => standardEvent,
getActions: () => actions,
getActionsContext: () => parent,
getActionsContext: () => context,
});
}
6 changes: 4 additions & 2 deletions src/vs/workbench/contrib/terminal/browser/terminalEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { openContextMenu } from 'vs/workbench/contrib/terminal/browser/terminalContextMenu';
import { ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { ICommandService } from 'vs/platform/commands/common/commands';

export class TerminalEditor extends EditorPane {

Expand All @@ -55,6 +56,7 @@ export class TerminalEditor extends EditorPane {
@IContextKeyService contextKeyService: IContextKeyService,
@IMenuService menuService: IMenuService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ICommandService private readonly _commandService: ICommandService,
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
@INotificationService private readonly _notificationService: INotificationService,
@ITerminalProfileService private readonly _terminalProfileService: ITerminalProfileService,
Expand Down Expand Up @@ -138,7 +140,7 @@ export class TerminalEditor extends EditorPane {

// copyPaste: Shift+right click should open context menu
if (rightClickBehavior === 'copyPaste' && event.shiftKey) {
openContextMenu(event, this._editorInstanceElement!, this._instanceMenu, this._contextMenuService);
openContextMenu(event, this._editorInput?.terminalInstance, this._instanceMenu, this._commandService, this._contextMenuService);
return;
}

Expand Down Expand Up @@ -176,7 +178,7 @@ export class TerminalEditor extends EditorPane {
else
if (!this._cancelContextMenu && rightClickBehavior !== 'copyPaste' && rightClickBehavior !== 'paste') {
if (!this._cancelContextMenu) {
openContextMenu(event, this._editorInstanceElement!, this._instanceMenu, this._contextMenuService);
openContextMenu(event, this._editorInput?.terminalInstance, this._instanceMenu, this._commandService, this._contextMenuService);
}
event.preventDefault();
event.stopImmediatePropagation();
Expand Down
21 changes: 15 additions & 6 deletions src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/termin
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
import { getInstanceHoverInfo } from 'vs/workbench/contrib/terminal/browser/terminalTooltip';
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
import { ICommandService } from 'vs/platform/commands/common/commands';

const $ = dom.$;

Expand All @@ -43,7 +44,6 @@ export class TerminalTabbedView extends Disposable {

private _terminalContainer: HTMLElement;
private _tabListElement: HTMLElement;
private _parentElement: HTMLElement;
private _tabContainer: HTMLElement;

private _tabList: TerminalTabList;
Expand Down Expand Up @@ -74,6 +74,7 @@ export class TerminalTabbedView extends Disposable {
@ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@INotificationService private readonly _notificationService: INotificationService,
@ICommandService private readonly _commandService: ICommandService,
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IMenuService menuService: IMenuService,
Expand All @@ -83,8 +84,6 @@ export class TerminalTabbedView extends Disposable {
) {
super();

this._parentElement = parentElement;

this._tabContainer = $('.tabs-container');
const tabListContainer = $('.tabs-list-container');
this._tabListElement = $('.tabs-list');
Expand Down Expand Up @@ -357,7 +356,7 @@ export class TerminalTabbedView extends Disposable {
else if (rightClickBehavior === 'copyPaste' || rightClickBehavior === 'paste') {
// copyPaste: Shift+right click should open context menu
if (rightClickBehavior === 'copyPaste' && event.shiftKey) {
openContextMenu(event, this._parentElement, this._instanceMenu, this._contextMenuService);
openContextMenu(event, terminal, this._instanceMenu, this._commandService, this._contextMenuService);
return;
}

Expand Down Expand Up @@ -389,8 +388,9 @@ export class TerminalTabbedView extends Disposable {
if (rightClickBehavior === 'nothing' && !event.shiftKey) {
this._cancelContextMenu = true;
}
terminalContainer.focus();
if (!this._cancelContextMenu) {
openContextMenu(event, this._parentElement, this._instanceMenu, this._contextMenuService);
openContextMenu(event, this._terminalGroupService.activeInstance!, this._instanceMenu, this._commandService, this._contextMenuService);
}
event.preventDefault();
event.stopImmediatePropagation();
Expand All @@ -406,7 +406,16 @@ export class TerminalTabbedView extends Disposable {
if (!emptyList) {
this._terminalGroupService.lastAccessedMenu = 'tab-list';
}
openContextMenu(event, this._parentElement, emptyList ? this._tabsListEmptyMenu : this._tabsListMenu, this._contextMenuService, emptyList ? this._getTabActions() : undefined);

// Put the focused item first as it's used as the first positional argument
const selectedInstances = this._tabList.getSelectedElements();
const focusedInstance = this._tabList.getFocusedElements()?.[0];
if (focusedInstance) {
selectedInstances.splice(selectedInstances.findIndex(e => e.instanceId === focusedInstance.instanceId), 1);
selectedInstances.unshift(focusedInstance);
}

openContextMenu(event, selectedInstances, emptyList ? this._tabsListEmptyMenu : this._tabsListMenu, this._commandService, this._contextMenuService, emptyList ? this._getTabActions() : undefined);
}
event.preventDefault();
event.stopImmediatePropagation();
Expand Down
9 changes: 9 additions & 0 deletions src/vs/workbench/contrib/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { MarshalledId } from 'vs/base/common/marshallingIds';
import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';
import Severity from 'vs/base/common/severity';
import { ThemeIcon } from 'vs/base/common/themables';
Expand Down Expand Up @@ -379,6 +380,14 @@ export interface ITerminalStatusHoverAction {
run: () => void;
}

/**
* Context for actions taken on terminal instances.
*/
export interface ISerializedTerminalInstanceContext {
$mid: MarshalledId.TerminalContext;
instanceId: number;
}

export const QUICK_LAUNCH_PROFILE_CHOICE = 'workbench.action.terminal.profile.choice';

export const enum TerminalCommandId {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,12 @@ const apiMenus: IAPIMenu[] = [
{
key: 'terminal/context',
id: MenuId.TerminalInstanceContext,
description: localize('menus.terminalContext', "The terminal context menu"),
proposed: 'terminalContextMenu'
description: localize('menus.terminalContext', "The terminal context menu")
},
{
key: 'terminal/title/context',
id: MenuId.TerminalTabContext,
description: localize('menus.terminalTabContext', "The terminal tabs context menu"),
proposed: 'terminalContextMenu'
description: localize('menus.terminalTabContext', "The terminal tabs context menu")
},
{
key: 'view/title',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export const allApiProposals = Object.freeze({
tabInputTextMerge: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts',
taskPresentationGroup: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts',
telemetry: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts',
terminalContextMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalContextMenu.d.ts',
terminalDataWriteEvent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts',
terminalDimensions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDimensions.d.ts',
terminalExecuteCommandEvent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalExecuteCommandEvent.d.ts',
Expand Down
12 changes: 0 additions & 12 deletions src/vscode-dts/vscode.proposed.terminalContextMenu.d.ts

This file was deleted.

Loading