merge with master

This commit is contained in:
Martin Aeschlimann
2018-08-09 15:15:07 +02:00
333 changed files with 8092 additions and 3804 deletions
@@ -413,6 +413,16 @@ export class IssueReporter extends Disposable {
if (cmdOrCtrlKey && e.keyCode === 189) {
this.applyZoom(webFrame.getZoomLevel() - 1);
}
// With latest electron upgrade, cmd+a is no longer propagating correctly for inputs in this window on mac
// Manually perform the selection
if (platform.isMacintosh) {
if (cmdOrCtrlKey && e.keyCode === 65 && e.target) {
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
(<HTMLInputElement>e.target).select();
}
}
}
};
}
+9 -1
View File
@@ -64,7 +64,7 @@ import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService';
import { MenubarChannel } from 'vs/platform/menubar/common/menubarIpc';
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { asArray } from 'vs/code/node/args';
import { CodeMenu } from 'vs/code/electron-main/menus';
export class CodeApplication {
@@ -520,6 +520,14 @@ export class CodeApplication {
}
}
// TODO@sbatten: Remove when switching back to dynamic menu
// Install Menu
const instantiationService = accessor.get(IInstantiationService);
const configurationService = accessor.get(IConfigurationService);
if (platform.isMacintosh || configurationService.getValue<string>('window.titleBarStyle') !== 'custom') {
instantiationService.createInstance(CodeMenu);
}
// Jump List
this.historyMainService.updateWindowsJumpList();
this.historyMainService.onRecentlyOpenedChange(() => this.historyMainService.updateWindowsJumpList());
+113 -1
View File
@@ -7,7 +7,14 @@
import * as nativeKeymap from 'native-keymap';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { IStateService } from 'vs/platform/state/common/state';
import { Event, Emitter, once } from 'vs/base/common/event';
import { ConfigWatcher } from 'vs/base/node/config';
import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ipcMain as ipc } from 'electron';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { ILogService } from 'vs/platform/log/common/log';
export class KeyboardLayoutMonitor {
@@ -31,4 +38,109 @@ export class KeyboardLayoutMonitor {
}
return this._emitter.event(callback);
}
}
export interface IKeybinding {
id: string;
label: string;
isNative: boolean;
}
export class KeybindingsResolver {
private static readonly lastKnownKeybindingsMapStorageKey = 'lastKnownKeybindings';
private commandIds: Set<string>;
private keybindings: { [commandId: string]: IKeybinding };
private keybindingsWatcher: ConfigWatcher<IUserFriendlyKeybinding[]>;
private _onKeybindingsChanged = new Emitter<void>();
onKeybindingsChanged: Event<void> = this._onKeybindingsChanged.event;
constructor(
@IStateService private stateService: IStateService,
@IEnvironmentService environmentService: IEnvironmentService,
@IWindowsMainService private windowsMainService: IWindowsMainService,
@ILogService private logService: ILogService
) {
this.commandIds = new Set<string>();
this.keybindings = this.stateService.getItem<{ [id: string]: string; }>(KeybindingsResolver.lastKnownKeybindingsMapStorageKey) || Object.create(null);
this.keybindingsWatcher = new ConfigWatcher<IUserFriendlyKeybinding[]>(environmentService.appKeybindingsPath, { changeBufferDelay: 100, onError: error => this.logService.error(error) });
this.registerListeners();
}
private registerListeners(): void {
// Listen to resolved keybindings from window
ipc.on('vscode:keybindingsResolved', (event, rawKeybindings: string) => {
let keybindings: IKeybinding[] = [];
try {
keybindings = JSON.parse(rawKeybindings);
} catch (error) {
// Should not happen
}
// Fill hash map of resolved keybindings and check for changes
let keybindingsChanged = false;
let keybindingsCount = 0;
const resolvedKeybindings: { [commandId: string]: IKeybinding } = Object.create(null);
keybindings.forEach(keybinding => {
keybindingsCount++;
resolvedKeybindings[keybinding.id] = keybinding;
if (!this.keybindings[keybinding.id] || keybinding.label !== this.keybindings[keybinding.id].label) {
keybindingsChanged = true;
}
});
// A keybinding might have been unassigned, so we have to account for that too
if (Object.keys(this.keybindings).length !== keybindingsCount) {
keybindingsChanged = true;
}
if (keybindingsChanged) {
this.keybindings = resolvedKeybindings;
this.stateService.setItem(KeybindingsResolver.lastKnownKeybindingsMapStorageKey, this.keybindings); // keep to restore instantly after restart
this._onKeybindingsChanged.fire();
}
});
// Resolve keybindings when any first window is loaded
const onceOnWindowReady = once(this.windowsMainService.onWindowReady);
onceOnWindowReady(win => this.resolveKeybindings(win));
// Resolve keybindings again when keybindings.json changes
this.keybindingsWatcher.onDidUpdateConfiguration(() => this.resolveKeybindings());
// Resolve keybindings when window reloads because an installed extension could have an impact
this.windowsMainService.onWindowReload(() => this.resolveKeybindings());
}
private resolveKeybindings(win = this.windowsMainService.getLastActiveWindow()): void {
if (this.commandIds.size && win) {
const commandIds: string[] = [];
this.commandIds.forEach(id => commandIds.push(id));
win.sendWhenReady('vscode:resolveKeybindings', JSON.stringify(commandIds));
}
}
public getKeybinding(commandId: string): IKeybinding {
if (!commandId) {
return void 0;
}
if (!this.commandIds.has(commandId)) {
this.commandIds.add(commandId);
}
return this.keybindings[commandId];
}
public dispose(): void {
this._onKeybindingsChanged.dispose();
this.keybindingsWatcher.dispose();
}
}
+42 -14
View File
@@ -31,12 +31,13 @@ export class Menubar {
private static readonly MAX_MENU_RECENT_ENTRIES = 10;
private isQuitting: boolean;
private appMenuInstalled: boolean;
private closedLastWindow: boolean;
private menuUpdater: RunOnceScheduler;
private nativeTabMenuItems: Electron.MenuItem[];
private menubarMenus: IMenubarData = {};
private menubarMenus: IMenubarData;
private keybindings: { [commandId: string]: IMenubarKeybinding };
@@ -54,6 +55,8 @@ export class Menubar {
this.keybindings = Object.create(null);
this.closedLastWindow = false;
this.install();
this.registerListeners();
@@ -112,8 +115,14 @@ export class Menubar {
return enableNativeTabs;
}
updateMenu(menus: IMenubarData, windowId: number) {
updateMenu(menus: IMenubarData, windowId: number, additionalKeybindings?: Array<IMenubarKeybinding>) {
this.menubarMenus = menus;
if (additionalKeybindings) {
additionalKeybindings.forEach(keybinding => {
this.keybindings[keybinding.id] = keybinding;
});
}
this.scheduleUpdateMenu();
}
@@ -143,9 +152,9 @@ export class Menubar {
return;
}
// Update menu if window count goes from N > 0 or 0 > N to update menu item enablement
if ((e.oldCount === 0 && e.newCount > 0) || (e.oldCount > 0 && e.newCount === 0)) {
this.closedLastWindow = e.newCount === 0;
this.scheduleUpdateMenu();
}
@@ -272,7 +281,7 @@ export class Menubar {
// Mac: Window
let macWindowMenuItem: Electron.MenuItem;
if (isMacintosh) {
if (this.shouldDrawMenu('Window')) {
const windowMenu = new Menu();
macWindowMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize('mWindow', "Window")), submenu: windowMenu, role: 'window' });
this.setMacWindowMenu(windowMenu);
@@ -310,7 +319,11 @@ export class Menubar {
menubar.append(helpMenuItem);
}
Menu.setApplicationMenu(menubar);
if (menubar.items && menubar.items.length > 0) {
Menu.setApplicationMenu(menubar);
} else {
Menu.setApplicationMenu(null);
}
}
private setMacApplicationMenu(macApplicationMenu: Electron.Menu): void {
@@ -370,14 +383,22 @@ export class Menubar {
switch (menuId) {
case 'File':
case 'Help':
return true;
if (isMacintosh) {
return (this.windowsMainService.getWindowCount() === 0 && this.closedLastWindow) || (!!this.menubarMenus && !!this.menubarMenus[menuId]);
}
case 'Window':
if (isMacintosh) {
return (this.windowsMainService.getWindowCount() === 0 && this.closedLastWindow) || !!this.menubarMenus;
}
default:
return this.windowsMainService.getWindowCount() > 0 && !!this.menubarMenus[menuId];
return this.windowsMainService.getWindowCount() > 0 && (!!this.menubarMenus && !!this.menubarMenus[menuId]);
}
}
private shouldFallback(menuId: string): boolean {
return this.shouldDrawMenu(menuId) && (this.windowsMainService.getWindowCount() === 0);
return this.shouldDrawMenu(menuId) && (this.windowsMainService.getWindowCount() === 0 && this.closedLastWindow && isMacintosh);
}
private setFallbackMenuById(menu: Electron.Menu, menuId: string): void {
@@ -462,16 +483,12 @@ export class Menubar {
});
}
const openProcessExplorer = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")), click: () => this.runActionInRenderer('workbench.action.openProcessExplorer') });
if (twitterItem) { menu.append(twitterItem); }
if (featureRequestsItem) { menu.append(featureRequestsItem); }
if (reportIssuesItem) { menu.append(reportIssuesItem); }
if (twitterItem || featureRequestsItem || reportIssuesItem) { menu.append(__separator__()); }
if ((twitterItem || featureRequestsItem || reportIssuesItem) && (licenseItem || privacyStatementItem)) { menu.append(__separator__()); }
if (licenseItem) { menu.append(licenseItem); }
if (privacyStatementItem) { menu.append(privacyStatementItem); }
if (licenseItem || privacyStatementItem) { menu.append(__separator__()); }
menu.append(openProcessExplorer);
break;
}
@@ -489,6 +506,8 @@ export class Menubar {
} else if (isMenubarMenuItemAction(item)) {
if (item.id === 'workbench.action.openRecent') {
this.insertRecentMenuItems(menu);
} else if (item.id === 'workbench.action.showAboutDialog') {
this.insertCheckForUpdatesItems(menu);
}
// Store the keybinding
@@ -505,11 +524,19 @@ export class Menubar {
}
private setMenuById(menu: Electron.Menu, menuId: string): void {
if (this.menubarMenus[menuId]) {
if (this.menubarMenus && this.menubarMenus[menuId]) {
this.setMenu(menu, this.menubarMenus[menuId].items);
}
}
private insertCheckForUpdatesItems(menu: Electron.Menu) {
const updateItems = this.getUpdateMenuItems();
if (updateItems.length) {
updateItems.forEach(i => menu.append(i));
menu.append(__separator__());
}
}
private insertRecentMenuItems(menu: Electron.Menu) {
const { workspaces, files } = this.historyMainService.getRecentlyOpened();
@@ -580,6 +607,7 @@ export class Menubar {
if (this.currentEnableNativeTabs) {
const hasMultipleWindows = this.windowsMainService.getWindowCount() > 1;
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mNewTab', "New Tab"), 'workbench.action.newWindowTab'));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowPreviousTab', "Show Previous Tab"), 'workbench.action.showPreviousWindowTab', hasMultipleWindows));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowNextTab', "Show Next Tab"), 'workbench.action.showNextWindowTab', hasMultipleWindows));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMoveTabToNewWindow', "Move Tab to New Window"), 'workbench.action.moveWindowTabToNewWindow', hasMultipleWindows));
File diff suppressed because it is too large Load Diff
+6
View File
@@ -500,6 +500,12 @@ export class CodeWindow implements ICodeWindow {
});
}
addTabbedWindow(window: ICodeWindow): void {
if (isMacintosh) {
this._win.addTabbedWindow(window.win);
}
}
load(config: IWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void {
// If this is the first time the window is loaded, we associate the paths
+24 -5
View File
@@ -82,6 +82,7 @@ interface IOpenBrowserWindowOptions {
filesToWait?: IPathsToWaitFor;
forceNewWindow?: boolean;
forceNewTabbedWindow?: boolean;
windowToUse?: ICodeWindow;
emptyWindowBackupFolder?: string;
@@ -547,7 +548,7 @@ export class WindowsManager implements IWindowsMainService {
// Special case: we started with --wait and we got back a folder to open. In this case
// we actually prefer to not open the folder but operate purely on the file.
if (typeof bestWindowOrFolder === 'string' && filesToWait) {
//TODO: #54483 Ben This should not happen
//TODO@Ben: #54483 This should not happen
console.error(`This should not happen`, bestWindowOrFolder, WindowsManager.WINDOWS);
bestWindowOrFolder = !openFilesInNewWindow ? this.getLastActiveWindow() : null;
}
@@ -581,7 +582,7 @@ export class WindowsManager implements IWindowsMainService {
// We found a suitable folder to open: add it to foldersToOpen
else if (typeof bestWindowOrFolder === 'string') {
//TODO: #54483 Ben This should not happen
//TODO@Ben: #54483 Ben This should not happen
// foldersToOpen.push(bestWindowOrFolder);
console.error(`This should not happen`, bestWindowOrFolder, WindowsManager.WINDOWS);
}
@@ -596,7 +597,8 @@ export class WindowsManager implements IWindowsMainService {
filesToCreate,
filesToDiff,
filesToWait,
forceNewWindow: true
forceNewWindow: true,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow
}));
// Reset these because we handled them
@@ -701,6 +703,7 @@ export class WindowsManager implements IWindowsMainService {
filesToDiff,
filesToWait,
forceNewWindow: true,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow,
emptyWindowBackupFolder
}));
@@ -721,7 +724,8 @@ export class WindowsManager implements IWindowsMainService {
userEnv: openConfig.userEnv,
cli: openConfig.cli,
initialStartup: openConfig.initialStartup,
forceNewWindow: openFolderInNewWindow
forceNewWindow: openFolderInNewWindow,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow
}));
openFolderInNewWindow = true; // any other window to open must open in new window then
@@ -768,6 +772,7 @@ export class WindowsManager implements IWindowsMainService {
filesToDiff,
filesToWait,
forceNewWindow,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow,
windowToUse
});
@@ -1147,6 +1152,7 @@ export class WindowsManager implements IWindowsMainService {
}
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
// Build IWindowConfiguration from config and options
const configuration: IWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI
configuration.appRoot = this.environmentService.appRoot;
@@ -1171,7 +1177,7 @@ export class WindowsManager implements IWindowsMainService {
}
let window: ICodeWindow;
if (!options.forceNewWindow) {
if (!options.forceNewWindow && !options.forceNewTabbedWindow) {
window = options.windowToUse || this.getLastActiveWindow();
if (window) {
window.focus();
@@ -1198,12 +1204,21 @@ export class WindowsManager implements IWindowsMainService {
state.mode = WindowMode.Normal;
}
// Create the window
window = this.instantiationService.createInstance(CodeWindow, {
state,
extensionDevelopmentPath: configuration.extensionDevelopmentPath,
isExtensionTestHost: !!configuration.extensionTestsPath
});
// Add as window tab if configured (macOS only)
if (options.forceNewTabbedWindow) {
const activeWindow = this.getLastActiveWindow();
if (activeWindow) {
activeWindow.addTabbedWindow(window);
}
}
// Add to our list of windows
WindowsManager.WINDOWS.push(window);
@@ -1494,6 +1509,10 @@ export class WindowsManager implements IWindowsMainService {
return this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
}
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
}
waitForWindowCloseOrLoad(windowId: number): TPromise<void> {
return new TPromise<void>(c => {
function handler(id: number) {
+2 -1
View File
@@ -11,8 +11,9 @@ import { OpenContext } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
import { getPathFromAmdModule } from 'vs/base/common/amd';
const fixturesFolder = require.toUrl('./fixtures');
const fixturesFolder = getPathFromAmdModule(require, './fixtures');
const testWorkspace: IWorkspaceIdentifier = {
id: Date.now().toString(),