Merge from vscode 817eb6b0c720a4ecbc13c020afbbebfed667aa09 (#7356)

This commit is contained in:
Anthony Dresser
2019-09-24 21:36:17 -07:00
committed by GitHub
parent a29ae4d3b9
commit 6a6048d40f
541 changed files with 7045 additions and 7287 deletions

View File

@@ -13,12 +13,12 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { IStateService } from 'vs/platform/state/common/state';
import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron';
import { parseLineAndColumnAware } from 'vs/code/node/paths';
import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
import product from 'vs/platform/product/common/product';
@@ -197,9 +197,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
const windowsStateStoreData = this.stateService.getItem<WindowsStateStorageData>(WindowsManager.windowsStateStorageKey);
this.windowsState = restoreWindowsState(windowsStateStoreData);
this.windowsState = restoreWindowsState(this.stateService.getItem<WindowsStateStorageData>(WindowsManager.windowsStateStorageKey));
if (!Array.isArray(this.windowsState.openedWindows)) {
this.windowsState.openedWindows = [];
}
@@ -227,7 +226,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
private registerListeners(): void {
// React to workbench ready events from windows
ipc.on('vscode:workbenchReady', (event: Electron.Event, windowId: number) => {
ipc.on('vscode:workbenchReady', (event: Event, windowId: number) => {
this.logService.trace('IPC#vscode-workbenchReady');
const win = this.getWindowById(windowId);
@@ -381,6 +380,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
};
}
async openExternal(url: string): Promise<boolean> {
shell.openExternal(url);
return true;
}
open(openConfig: IOpenConfiguration): ICodeWindow[] {
this.logService.trace('windowsManager#open');
openConfig = this.validateOpenConfig(openConfig);
@@ -867,7 +872,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
message = localize('uriInvalidTitle', "URI can not be opened");
detail = localize('uriInvalidDetail', "The URI '{0}' is not valid and can not be opened.", uri.toString());
}
const options: Electron.MessageBoxOptions = {
const options: MessageBoxOptions = {
title: product.nameLong,
type: 'info',
buttons: [localize('ok', "OK")],
@@ -1468,7 +1473,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
//
// We want the new window to open on the same display that the last active one is in
let displayToUse: Electron.Display | undefined;
let displayToUse: Display | undefined;
const displays = screen.getAllDisplays();
// Single Display
@@ -1605,13 +1610,13 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority));
}
openNewWindow(context: OpenContext, options?: INewWindowOptions): ICodeWindow[] {
openEmptyWindow(context: OpenContext, options?: { reuse?: boolean, remoteAuthority?: string }): ICodeWindow[] {
let cli = this.environmentService.args;
const remote = options && options.remoteAuthority || undefined;
const remote = options && options.remoteAuthority;
if (cli && (cli.remote !== remote)) {
cli = { ...cli, remote };
}
const forceReuseWindow = options && options.reuseWindow;
const forceReuseWindow = options && options.reuse;
const forceNewWindow = !forceReuseWindow;
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
}
@@ -1665,11 +1670,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
getWindowById(windowId: number): ICodeWindow | undefined {
const res = WindowsManager.WINDOWS.filter(window => window.id === windowId);
if (res && res.length === 1) {
return res[0];
}
return undefined;
return arrays.firstOrDefault(res);
}
getWindows(): ICodeWindow[] {
@@ -1714,9 +1715,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return; // Return early if the window has been going down already
}
if (result.button === 0) {
if (result.response === 0) {
window.reload();
} else if (result.button === 2) {
} else if (result.response === 2) {
this.onBeforeWindowClose(window); // 'close' event will not be fired on destroy(), so run it manually
window.win.destroy(); // make sure to destroy the window as it is unresponsive
}
@@ -1737,9 +1738,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return; // Return early if the window has been going down already
}
if (result.button === 0) {
if (result.response === 0) {
window.reload();
} else if (result.button === 1) {
} else if (result.response === 1) {
this.onBeforeWindowClose(window); // 'close' event will not be fired on destroy(), so run it manually
window.win.destroy(); // make sure to destroy the window as it has crashed
}
@@ -1761,7 +1762,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this._onWindowClose.fire(win.id);
}
async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('open', "Open");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title });
if (paths) {
@@ -1773,7 +1774,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}));
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen,
forceNewWindow: options.forceNewWindow
@@ -1781,14 +1782,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFolder', "Open Folder");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, title });
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ folderUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
@@ -1796,14 +1797,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFile', "Open File");
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title });
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ fileUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
@@ -1811,7 +1812,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openWorkspaceTitle', "Open Workspace");
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
const filters = WORKSPACE_FILTER;
@@ -1820,7 +1821,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ workspaceUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
@@ -1842,15 +1843,15 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
});
}
showMessageBox(options: Electron.MessageBoxOptions, win?: ICodeWindow): Promise<IMessageBoxResult> {
showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise<MessageBoxReturnValue> {
return this.dialogs.showMessageBox(options, win);
}
showSaveDialog(options: Electron.SaveDialogOptions, win?: ICodeWindow): Promise<string> {
showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise<SaveDialogReturnValue> {
return this.dialogs.showSaveDialog(options, win);
}
showOpenDialog(options: Electron.OpenDialogOptions, win?: ICodeWindow): Promise<string[]> {
showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise<OpenDialogReturnValue> {
return this.dialogs.showOpenDialog(options, win);
}
@@ -1897,10 +1898,10 @@ class Dialogs {
this.noWindowDialogQueue = new Queue<void>();
}
async pick(options: IInternalNativeOpenDialogOptions): Promise<string[] | undefined> {
async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise<string[] | undefined> {
// Ensure dialog options
const dialogOptions: Electron.OpenDialogOptions = {
const dialogOptions: OpenDialogOptions = {
title: options.title,
buttonLabel: options.buttonLabel,
filters: options.filters
@@ -1928,15 +1929,15 @@ class Dialogs {
}
// Show Dialog
const focusedWindow = (typeof options.windowId === 'number' ? this.windowsMainService.getWindowById(options.windowId) : undefined) || this.windowsMainService.getFocusedWindow();
const windowToUse = win || this.windowsMainService.getFocusedWindow();
const paths = await this.showOpenDialog(dialogOptions, focusedWindow);
if (paths && paths.length > 0) {
const result = await this.showOpenDialog(dialogOptions, windowToUse);
if (result && result.filePaths && result.filePaths.length > 0) {
// Remember path in storage for next time
this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(paths[0]));
this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(result.filePaths[0]));
return paths;
return result.filePaths;
}
return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check
@@ -1956,20 +1957,17 @@ class Dialogs {
return windowDialogQueue;
}
showMessageBox(options: Electron.MessageBoxOptions, window?: ICodeWindow): Promise<IMessageBoxResult> {
showMessageBox(options: MessageBoxOptions, window?: ICodeWindow): Promise<MessageBoxReturnValue> {
return this.getDialogQueue(window).queue(async () => {
let result: Electron.MessageBoxReturnValue;
if (window) {
result = await dialog.showMessageBox(window.win, options);
} else {
result = await dialog.showMessageBox(options);
return dialog.showMessageBox(window.win, options);
}
return { button: result.response, checkboxChecked: result.checkboxChecked };
return dialog.showMessageBox(options);
});
}
showSaveDialog(options: Electron.SaveDialogOptions, window?: ICodeWindow): Promise<string> {
showSaveDialog(options: SaveDialogOptions, window?: ICodeWindow): Promise<SaveDialogReturnValue> {
function normalizePath(path: string | undefined): string | undefined {
if (path && isMacintosh) {
@@ -1980,18 +1978,20 @@ class Dialogs {
}
return this.getDialogQueue(window).queue(async () => {
let result: Electron.SaveDialogReturnValue;
let result: SaveDialogReturnValue;
if (window) {
result = await dialog.showSaveDialog(window.win, options);
} else {
result = await dialog.showSaveDialog(options);
}
return normalizePath(result.filePath);
result.filePath = normalizePath(result.filePath);
return result;
});
}
showOpenDialog(options: Electron.OpenDialogOptions, window?: ICodeWindow): Promise<string[]> {
showOpenDialog(options: OpenDialogOptions, window?: ICodeWindow): Promise<OpenDialogReturnValue> {
function normalizePaths(paths: string[] | undefined): string[] | undefined {
if (paths && paths.length > 0 && isMacintosh) {
@@ -2012,14 +2012,16 @@ class Dialogs {
}
// Show dialog
let result: Electron.OpenDialogReturnValue;
let result: OpenDialogReturnValue;
if (window) {
result = await dialog.showOpenDialog(window.win, options);
} else {
result = await dialog.showOpenDialog(options);
}
return normalizePaths(result.filePaths);
result.filePaths = normalizePaths(result.filePaths);
return result;
});
}
}
@@ -2056,7 +2058,7 @@ class WorkspacesManager {
// Prevent overwriting a workspace that is currently opened in another window
if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) {
const options: Electron.MessageBoxOptions = {
const options: MessageBoxOptions = {
title: product.nameLong,
type: 'info',
buttons: [localize('ok', "OK")],