Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -3,15 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
export const IMenubarService = createDecorator<IMenubarService>('menubarService');
export interface IMenubarService {
_serviceBrand: any;
updateMenubar(windowId: number, menuData: IMenubarData): TPromise<void>;
updateMenubar(windowId: number, menuData: IMenubarData): Promise<void>;
}
export interface IMenubarData {
@@ -25,6 +25,7 @@ export interface IMenubarMenu {
export interface IMenubarKeybinding {
label: string;
userSettingsLabel: string;
isNative?: boolean; // Assumed true if missing
}
@@ -35,6 +36,13 @@ export interface IMenubarMenuItemAction {
enabled?: boolean; // Assumed true if missing
}
export interface IMenubarMenuUriItemAction {
id: string;
label: string;
uri: URI;
enabled?: boolean;
}
export interface IMenubarMenuItemSubmenu {
id: string;
label: string;
@@ -45,7 +53,7 @@ export interface IMenubarMenuItemSeparator {
id: 'vscode.menubar.separator';
}
export type MenubarMenuItem = IMenubarMenuItemAction | IMenubarMenuItemSubmenu | IMenubarMenuItemSeparator;
export type MenubarMenuItem = IMenubarMenuItemAction | IMenubarMenuItemSubmenu | IMenubarMenuItemSeparator | IMenubarMenuUriItemAction;
export function isMenubarMenuItemSubmenu(menuItem: MenubarMenuItem): menuItem is IMenubarMenuItemSubmenu {
return (<IMenubarMenuItemSubmenu>menuItem).submenu !== undefined;
@@ -55,6 +63,10 @@ export function isMenubarMenuItemSeparator(menuItem: MenubarMenuItem): menuItem
return (<IMenubarMenuItemSeparator>menuItem).id === 'vscode.menubar.separator';
}
export function isMenubarMenuItemUriAction(menuItem: MenubarMenuItem): menuItem is IMenubarMenuUriItemAction {
return (<IMenubarMenuUriItemAction>menuItem).uri !== undefined;
}
export function isMenubarMenuItemAction(menuItem: MenubarMenuItem): menuItem is IMenubarMenuItemAction {
return !isMenubarMenuItemSubmenu(menuItem) && !isMenubarMenuItemSeparator(menuItem);
}
return !isMenubarMenuItemSubmenu(menuItem) && !isMenubarMenuItemSeparator(menuItem) && !isMenubarMenuItemUriAction(menuItem);
}

View File

@@ -7,20 +7,18 @@ import * as nls from 'vs/nls';
import { isMacintosh, language } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { app, shell, Menu, MenuItem, BrowserWindow } from 'electron';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle } from 'vs/platform/windows/common/windows';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
import product from 'vs/platform/node/product';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mnemonicMenuLabel as baseMnemonicLabel, unmnemonicLabel } from 'vs/base/common/labels';
import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels';
import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService } from 'vs/platform/history/common/history';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu } from 'vs/platform/menubar/common/menubar';
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/common/menubar';
import { URI } from 'vs/base/common/uri';
import { ILabelService } from 'vs/platform/label/common/label';
import { IStateService } from 'vs/platform/state/common/state';
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
@@ -31,9 +29,17 @@ interface IMenuItemClickHandler {
inNoWindow: () => void;
}
type IMenuItemInvocation = (
{ type: 'commandId'; commandId: string; }
| { type: 'keybinding'; userSettingsLabel: string; }
);
interface IMenuItemWithKeybinding {
userSettingsLabel?: string;
}
export class Menubar {
private static readonly MAX_MENU_RECENT_ENTRIES = 10;
private static readonly lastKnownMenubarStorageKey = 'lastKnownMenubarData';
private willShutdown: boolean;
@@ -54,16 +60,15 @@ export class Menubar {
private fallbackMenuHandlers: { [id: string]: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Electron.Event) => void } = {};
constructor(
@IUpdateService private updateService: IUpdateService,
@IUpdateService private readonly updateService: IUpdateService,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService private configurationService: IConfigurationService,
@IWindowsMainService private windowsMainService: IWindowsMainService,
@IEnvironmentService private environmentService: IEnvironmentService,
@ITelemetryService private telemetryService: ITelemetryService,
@IHistoryMainService private historyMainService: IHistoryMainService,
@ILabelService private labelService: ILabelService,
@IStateService private stateService: IStateService,
@ILifecycleService private lifecycleService: ILifecycleService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IHistoryMainService private readonly historyMainService: IHistoryMainService,
@IStateService private readonly stateService: IStateService,
@ILifecycleService private readonly lifecycleService: ILifecycleService
) {
this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0);
@@ -88,10 +93,6 @@ export class Menubar {
}
private restoreCachedMenubarData() {
// TODO@sbatten remove this at some point down the road
const outdatedKeys = ['lastKnownAdditionalKeybindings', 'lastKnownKeybindings', 'lastKnownMenubar'];
outdatedKeys.forEach(key => this.stateService.removeItem(key));
const menubarData = this.stateService.getItem<IMenubarData>(Menubar.lastKnownMenubarStorageKey);
if (menubarData) {
if (menubarData.menus) {
@@ -151,22 +152,11 @@ export class Menubar {
}
private registerListeners(): void {
// Keep flag when app quits
this.lifecycleService.onWillShutdown(() => this.willShutdown = true);
// // Listen to some events from window service to update menu
this.historyMainService.onRecentlyOpenedChange(() => this.scheduleUpdateMenu());
this.windowsMainService.onWindowsCountChanged(e => this.onWindowsCountChanged(e));
// this.windowsMainService.onActiveWindowChanged(() => this.updateWorkspaceMenuItems());
// this.windowsMainService.onWindowReady(() => this.updateWorkspaceMenuItems());
// this.windowsMainService.onWindowClose(() => this.updateWorkspaceMenuItems());
// Update when auto save config changes
// this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e));
// Listen to update service
// this.updateService.onStateChange(() => this.updateMenu());
}
private get currentEnableMenuBarMnemonics(): boolean {
@@ -255,7 +245,8 @@ export class Menubar {
let macApplicationMenuItem: Electron.MenuItem;
if (isMacintosh) {
const applicationMenu = new Menu();
macApplicationMenuItem = new MenuItem({ label: product.nameShort, submenu: applicationMenu });
// {{SQL CARBON EDIT}} - Use long name
macApplicationMenuItem = new MenuItem({ label: product.nameLong, submenu: applicationMenu });
this.setMacApplicationMenu(applicationMenu);
menubar.append(macApplicationMenuItem);
}
@@ -284,12 +275,14 @@ export class Menubar {
this.setMenuById(editMenu, 'Edit');
menubar.append(editMenuItem);
// Selection
const selectionMenu = new Menu();
const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu });
// {{SQL CARBON EDIT}} - Disable unused menus
// // Selection
// const selectionMenu = new Menu();
// const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu });
this.setMenuById(selectionMenu, 'Selection');
menubar.append(selectionMenuItem);
// this.setMenuById(selectionMenu, 'Selection');
// menubar.append(selectionMenuItem);
// {{SQL CARBON EDIT}} - End
// View
const viewMenu = new Menu();
@@ -298,26 +291,32 @@ export class Menubar {
this.setMenuById(viewMenu, 'View');
menubar.append(viewMenuItem);
// Go
const gotoMenu = new Menu();
const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
// {{SQL CARBON EDIT}} - Disable unused menus
// // Go
// const gotoMenu = new Menu();
// const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
this.setMenuById(gotoMenu, 'Go');
menubar.append(gotoMenuItem);
// this.setMenuById(gotoMenu, 'Go');
// menubar.append(gotoMenuItem);
// {{SQL CARBON EDIT}} - End
// Debug
const debugMenu = new Menu();
const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug")), submenu: debugMenu });
// {{SQL CARBON EDIT}} - Disable unused menus
// // Debug
// const debugMenu = new Menu();
// const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug")), submenu: debugMenu });
this.setMenuById(debugMenu, 'Debug');
menubar.append(debugMenuItem);
// this.setMenuById(debugMenu, 'Debug');
// menubar.append(debugMenuItem);
// {{SQL CARBON EDIT}} - End
// Terminal
const terminalMenu = new Menu();
const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu });
// {{SQL CARBON EDIT}} - Disable unused menus
// // Terminal
// const terminalMenu = new Menu();
// const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu });
this.setMenuById(terminalMenu, 'Terminal');
menubar.append(terminalMenuItem);
// this.setMenuById(terminalMenu, 'Terminal');
// menubar.append(terminalMenuItem);
// {{SQL CARBON EDIT}} - End
// Mac: Window
let macWindowMenuItem: Electron.MenuItem | undefined;
@@ -433,10 +432,10 @@ export class Menubar {
const submenuItem = new MenuItem({ label: this.mnemonicLabel(item.label), submenu: submenu });
this.setMenu(submenu, item.submenu.items);
menu.append(submenuItem);
} else if (isMenubarMenuItemUriAction(item)) {
menu.append(this.createOpenRecentMenuItem(item.uri, item.label, item.id, item.id === 'openRecentFile'));
} else if (isMenubarMenuItemAction(item)) {
if (item.id === 'workbench.action.openRecent') {
this.insertRecentMenuItems(menu);
} else if (item.id === 'workbench.action.showAboutDialog') {
if (item.id === 'workbench.action.showAboutDialog') {
this.insertCheckForUpdatesItems(menu);
}
@@ -472,41 +471,8 @@ export class Menubar {
}
}
private insertRecentMenuItems(menu: Electron.Menu) {
const { workspaces, files } = this.historyMainService.getRecentlyOpened();
// Workspaces
if (workspaces.length > 0) {
for (let i = 0; i < Menubar.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {
menu.append(this.createOpenRecentMenuItem(workspaces[i], 'openRecentWorkspace', false));
}
menu.append(__separator__());
}
// Files
if (files.length > 0) {
for (let i = 0; i < Menubar.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
menu.append(this.createOpenRecentMenuItem(files[i], 'openRecentFile', true));
}
menu.append(__separator__());
}
}
private createOpenRecentMenuItem(workspaceOrFile: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI, commandId: string, isFile: boolean): Electron.MenuItem {
let label: string;
let uri: URI;
if (isSingleFolderWorkspaceIdentifier(workspaceOrFile) && !isFile) {
label = unmnemonicLabel(this.labelService.getWorkspaceLabel(workspaceOrFile, { verbose: true }));
uri = workspaceOrFile;
} else if (isWorkspaceIdentifier(workspaceOrFile)) {
label = this.labelService.getWorkspaceLabel(workspaceOrFile, { verbose: true });
uri = URI.file(workspaceOrFile.configPath);
} else {
label = unmnemonicLabel(this.labelService.getUriLabel(workspaceOrFile));
uri = workspaceOrFile;
}
private createOpenRecentMenuItem(uri: URI, label: string, commandId: string, isFile: boolean): Electron.MenuItem {
const revivedUri = URI.revive(uri);
return new MenuItem(this.likeAction(commandId, {
label,
@@ -515,13 +481,13 @@ export class Menubar {
const success = this.windowsMainService.open({
context: OpenContext.MENU,
cli: this.environmentService.args,
urisToOpen: [uri],
urisToOpen: [revivedUri],
forceNewWindow: openInNewWindow,
forceOpenWorkspaceAsFile: isFile
}).length > 0;
if (!success) {
this.historyMainService.removeFromRecentlyOpened([workspaceOrFile]);
this.historyMainService.removeFromRecentlyOpened([revivedUri]);
}
}
}, false));
@@ -621,17 +587,49 @@ export class Menubar {
}
}
private static _menuItemIsTriggeredViaKeybinding(event: Electron.Event, userSettingsLabel: string): boolean {
// The event coming in from Electron will inform us only about the modifier keys pressed.
// The strategy here is to check if the modifier keys match those of the keybinding,
// since it is highly unlikely to use modifier keys when clicking with the mouse
if (!userSettingsLabel) {
// There is no keybinding
return false;
}
let ctrlRequired = /ctrl/.test(userSettingsLabel);
let shiftRequired = /shift/.test(userSettingsLabel);
let altRequired = /alt/.test(userSettingsLabel);
let metaRequired = /cmd/.test(userSettingsLabel) || /super/.test(userSettingsLabel);
if (!ctrlRequired && !shiftRequired && !altRequired && !metaRequired) {
// This keybinding does not use any modifier keys, so we cannot use this heuristic
return false;
}
return (
ctrlRequired === event.ctrlKey
&& shiftRequired === event.shiftKey
&& altRequired === event.altKey
&& metaRequired === event.metaKey
);
}
private createMenuItem(label: string, commandId: string | string[], enabled?: boolean, checked?: boolean): Electron.MenuItem;
private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): Electron.MenuItem;
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem {
const label = this.mnemonicLabel(arg1);
const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: Electron.MenuItem, win: Electron.BrowserWindow, event: Electron.Event) => {
const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: Electron.MenuItem & IMenuItemWithKeybinding, win: Electron.BrowserWindow, event: Electron.Event) => {
const userSettingsLabel = menuItem ? menuItem.userSettingsLabel : null;
let commandId = arg2;
if (Array.isArray(arg2)) {
commandId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking
}
this.runActionInRenderer(commandId);
if (userSettingsLabel && Menubar._menuItemIsTriggeredViaKeybinding(event, userSettingsLabel)) {
this.runActionInRenderer({ type: 'keybinding', userSettingsLabel });
} else {
this.runActionInRenderer({ type: 'commandId', commandId });
}
};
const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsMainService.getWindowCount() > 0;
const checked = typeof arg4 === 'boolean' ? arg4 : false;
@@ -704,7 +702,7 @@ export class Menubar {
};
}
private runActionInRenderer(id: string): void {
private runActionInRenderer(invocation: IMenuItemInvocation): void {
// We make sure to not run actions when the window has no focus, this helps
// for https://github.com/Microsoft/vscode/issues/25907 and specifically for
// https://github.com/Microsoft/vscode/issues/11928
@@ -719,18 +717,24 @@ export class Menubar {
}
if (activeWindow) {
if (!activeWindow.isReady && isMacintosh && id === 'workbench.action.toggleDevTools' && !this.environmentService.isBuilt) {
// prevent this action from running twice on macOS (https://github.com/Microsoft/vscode/issues/62719)
// we already register a keybinding in bootstrap-window.js for opening developer tools in case something
// goes wrong and that keybinding is only removed when the application has loaded (= window ready).
return;
if (isMacintosh && !this.environmentService.isBuilt && !activeWindow.isReady) {
if ((invocation.type === 'commandId' && invocation.commandId === 'workbench.action.toggleDevTools') || (invocation.type !== 'commandId' && invocation.userSettingsLabel === 'alt+cmd+i')) {
// prevent this action from running twice on macOS (https://github.com/Microsoft/vscode/issues/62719)
// we already register a keybinding in bootstrap-window.js for opening developer tools in case something
// goes wrong and that keybinding is only removed when the application has loaded (= window ready).
return;
}
}
this.windowsMainService.sendToFocused('vscode:runAction', { id, from: 'menu' } as IRunActionInWindowRequest);
if (invocation.type === 'commandId') {
this.windowsMainService.sendToFocused('vscode:runAction', { id: invocation.commandId, from: 'menu' } as IRunActionInWindowRequest);
} else {
this.windowsMainService.sendToFocused('vscode:runKeybinding', { userSettingsLabel: invocation.userSettingsLabel } as IRunKeybindingInWindowRequest);
}
}
}
private withKeybinding(commandId: string | undefined, options: Electron.MenuItemConstructorOptions): Electron.MenuItemConstructorOptions {
private withKeybinding(commandId: string | undefined, options: Electron.MenuItemConstructorOptions & IMenuItemWithKeybinding): Electron.MenuItemConstructorOptions {
const binding = typeof commandId === 'string' ? this.keybindings[commandId] : undefined;
// Apply binding if there is one
@@ -739,6 +743,7 @@ export class Menubar {
// if the binding is native, we can just apply it
if (binding.isNative !== false) {
options.accelerator = binding.label;
options.userSettingsLabel = binding.userSettingsLabel;
}
// the keybinding is not native so we cannot show it as part of the accelerator of
@@ -755,7 +760,7 @@ export class Menubar {
// Unset bindings if there is none
else {
options.accelerator = void 0;
options.accelerator = undefined;
}
return options;

View File

@@ -6,7 +6,6 @@
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { Menubar } from 'vs/platform/menubar/electron-main/menubar';
import { ILogService } from 'vs/platform/log/common/log';
import { TPromise } from 'vs/base/common/winjs.base';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class MenubarService implements IMenubarService {
@@ -15,20 +14,20 @@ export class MenubarService implements IMenubarService {
private _menubar: Menubar;
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@ILogService private logService: ILogService
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ILogService private readonly logService: ILogService
) {
// Install Menu
this._menubar = this.instantiationService.createInstance(Menubar);
}
updateMenubar(windowId: number, menus: IMenubarData): TPromise<void> {
updateMenubar(windowId: number, menus: IMenubarData): Promise<void> {
this.logService.trace('menubarService#updateMenubar', windowId);
if (this._menubar) {
this._menubar.updateMenu(menus, windowId);
}
return TPromise.as(void 0);
return Promise.resolve(undefined);
}
}

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc';
import { TPromise } from 'vs/base/common/winjs.base';
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { Event } from 'vs/base/common/event';
@@ -15,7 +14,7 @@ export class MenubarChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): TPromise<any> {
call(_, command: string, arg?: any): Promise<any> {
switch (command) {
case 'updateMenubar': return this.service.updateMenubar(arg[0], arg[1]);
}
@@ -30,7 +29,7 @@ export class MenubarChannelClient implements IMenubarService {
constructor(private channel: IChannel) { }
updateMenubar(windowId: number, menuData: IMenubarData): TPromise<void> {
updateMenubar(windowId: number, menuData: IMenubarData): Promise<void> {
return this.channel.call('updateMenubar', [windowId, menuData]);
}
}
}