Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.context-view .monaco-menu {
min-width: 130px;
}

View File

@@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./contextMenuHandler';
import { ActionRunner, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Menu } from 'vs/base/browser/ui/menu/menu';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { EventType, $, isHTMLElement } from 'vs/base/browser/dom';
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { domEvent } from 'vs/base/browser/event';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
export interface IContextMenuHandlerOptions {
blockMouse: boolean;
}
export class ContextMenuHandler {
private focusToReturn: HTMLElement | null = null;
private block: HTMLElement | null = null;
private options: IContextMenuHandlerOptions = { blockMouse: true };
constructor(
private contextViewService: IContextViewService,
private telemetryService: ITelemetryService,
private notificationService: INotificationService,
private keybindingService: IKeybindingService,
private themeService: IThemeService
) { }
configure(options: IContextMenuHandlerOptions): void {
this.options = options;
}
showContextMenu(delegate: IContextMenuDelegate): void {
const actions = delegate.getActions();
if (!actions.length) {
return; // Don't render an empty context menu
}
this.focusToReturn = document.activeElement as HTMLElement;
let menu: Menu | undefined;
let shadowRootElement = isHTMLElement(delegate.domForShadowRoot) ? delegate.domForShadowRoot : undefined;
this.contextViewService.showContextView({
getAnchor: () => delegate.getAnchor(),
canRelayout: false,
anchorAlignment: delegate.anchorAlignment,
render: (container) => {
let className = delegate.getMenuClassName ? delegate.getMenuClassName() : '';
if (className) {
container.className += ' ' + className;
}
// Render invisible div to block mouse interaction in the rest of the UI
if (this.options.blockMouse) {
this.block = container.appendChild($('.context-view-block'));
this.block.style.position = 'fixed';
this.block.style.cursor = 'initial';
this.block.style.left = '0';
this.block.style.top = '0';
this.block.style.width = '100%';
this.block.style.height = '100%';
this.block.style.zIndex = '-1';
domEvent(this.block, EventType.MOUSE_DOWN)((e: MouseEvent) => e.stopPropagation());
}
const menuDisposables = new DisposableStore();
const actionRunner = delegate.actionRunner || new ActionRunner();
actionRunner.onDidBeforeRun(this.onActionRun, this, menuDisposables);
actionRunner.onDidRun(this.onDidActionRun, this, menuDisposables);
menu = new Menu(container, actions, {
actionViewItemProvider: delegate.getActionViewItem,
context: delegate.getActionsContext ? delegate.getActionsContext() : null,
actionRunner,
getKeyBinding: delegate.getKeyBinding ? delegate.getKeyBinding : action => this.keybindingService.lookupKeybinding(action.id)
});
menuDisposables.add(attachMenuStyler(menu, this.themeService));
menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);
menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);
domEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);
domEvent(window, EventType.MOUSE_DOWN)((e: MouseEvent) => {
if (e.defaultPrevented) {
return;
}
let event = new StandardMouseEvent(e);
let element: HTMLElement | null = event.target;
// Don't do anything as we are likely creating a context menu
if (event.rightButton) {
return;
}
while (element) {
if (element === container) {
return;
}
element = element.parentElement;
}
this.contextViewService.hideContextView(true);
}, null, menuDisposables);
return combinedDisposable(menuDisposables, menu);
},
focus: () => {
if (menu) {
menu.focus(!!delegate.autoSelectFirstItem);
}
},
onHide: (didCancel?: boolean) => {
if (delegate.onHide) {
delegate.onHide(!!didCancel);
}
if (this.block) {
this.block.remove();
this.block = null;
}
if (this.focusToReturn) {
this.focusToReturn.focus();
}
}
}, shadowRootElement, !!shadowRootElement);
}
private onActionRun(e: IRunEvent): void {
if (this.telemetryService) {
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: e.action.id, from: 'contextMenu' });
}
this.contextViewService.hideContextView(false);
// Restore focus here
if (this.focusToReturn) {
this.focusToReturn.focus();
}
}
private onDidActionRun(e: IRunEvent): void {
if (e.error && this.notificationService) {
this.notificationService.error(e.error);
}
}
}

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ContextMenuHandler, IContextMenuHandlerOptions } from './contextMenuHandler';
import { IContextViewService, IContextMenuService } from './contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Disposable } from 'vs/base/common/lifecycle';
import { ModifierKeyEmitter } from 'vs/base/browser/dom';
export class ContextMenuService extends Disposable implements IContextMenuService {
declare readonly _serviceBrand: undefined;
private contextMenuHandler: ContextMenuHandler;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@INotificationService notificationService: INotificationService,
@IContextViewService contextViewService: IContextViewService,
@IKeybindingService keybindingService: IKeybindingService,
@IThemeService themeService: IThemeService
) {
super();
this.contextMenuHandler = new ContextMenuHandler(contextViewService, telemetryService, notificationService, keybindingService, themeService);
}
configure(options: IContextMenuHandlerOptions): void {
this.contextMenuHandler.configure(options);
}
// ContextMenu
showContextMenu(delegate: IContextMenuDelegate): void {
this.contextMenuHandler.showContextMenu(delegate);
ModifierKeyEmitter.getInstance().resetKeyStatus();
}
}

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { AnchorAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
export const IContextViewService = createDecorator<IContextViewService>('contextViewService');
export interface IContextViewService extends IContextViewProvider {
readonly _serviceBrand: undefined;
showContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable;
hideContextView(data?: any): void;
getContextViewElement(): HTMLElement;
layout(): void;
anchorAlignment?: AnchorAlignment;
}
export interface IContextViewDelegate {
canRelayout?: boolean; // Default: true
getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; };
render(container: HTMLElement): IDisposable;
onDOMEvent?(e: any, activeElement: HTMLElement): void;
onHide?(data?: any): void;
focus?(): void;
anchorAlignment?: AnchorAlignment;
}
export const IContextMenuService = createDecorator<IContextMenuService>('contextMenuService');
export interface IContextMenuService {
readonly _serviceBrand: undefined;
showContextMenu(delegate: IContextMenuDelegate): void;
}

View File

@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IContextViewService, IContextViewDelegate } from './contextView';
import { ContextView, ContextViewDOMPosition } from 'vs/base/browser/ui/contextview/contextview';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
export class ContextViewService extends Disposable implements IContextViewService {
declare readonly _serviceBrand: undefined;
private currentViewDisposable: IDisposable = Disposable.None;
private contextView: ContextView;
private container: HTMLElement;
constructor(
@ILayoutService readonly layoutService: ILayoutService
) {
super();
this.container = layoutService.container;
this.contextView = this._register(new ContextView(this.container, ContextViewDOMPosition.ABSOLUTE));
this.layout();
this._register(layoutService.onLayout(() => this.layout()));
}
// ContextView
setContainer(container: HTMLElement, domPosition?: ContextViewDOMPosition): void {
this.contextView.setContainer(container, domPosition || ContextViewDOMPosition.ABSOLUTE);
}
showContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable {
if (container) {
if (container !== this.container) {
this.container = container;
this.setContainer(container, shadowRoot ? ContextViewDOMPosition.FIXED_SHADOW : ContextViewDOMPosition.FIXED);
}
} else {
if (this.container !== this.layoutService.container) {
this.container = this.layoutService.container;
this.setContainer(this.container, ContextViewDOMPosition.ABSOLUTE);
}
}
this.contextView.show(delegate);
const disposable = toDisposable(() => {
if (this.currentViewDisposable === disposable) {
this.hideContextView();
}
});
this.currentViewDisposable = disposable;
return disposable;
}
getContextViewElement(): HTMLElement {
return this.contextView.getViewElement();
}
layout(): void {
this.contextView.layout();
}
hideContextView(data?: any): void {
this.contextView.hide(data);
}
}