Merge from vscode 5b9869eb02fa4c96205a74d05cad9164dfd06d60 (#5607)

This commit is contained in:
Anthony Dresser
2019-05-24 12:20:30 -07:00
committed by GitHub
parent 361ada4963
commit bcc449b524
126 changed files with 3096 additions and 2255 deletions

View File

@@ -113,11 +113,10 @@ export class OpenNewsletterSignupUrlAction extends Action {
this.telemetryService = telemetryService;
}
run(): Promise<void> {
this.telemetryService.getTelemetryInfo().then(info => {
window.open(`${OpenNewsletterSignupUrlAction.URL}?machineId=${encodeURIComponent(info.machineId)}`);
});
return Promise.resolve();
async run(): Promise<void> {
const info = await this.telemetryService.getTelemetryInfo();
window.open(`${OpenNewsletterSignupUrlAction.URL}?machineId=${encodeURIComponent(info.machineId)}`);
}
}

View File

@@ -86,7 +86,7 @@ export abstract class BaseZoomAction extends Action {
super(id, label);
}
protected setConfiguredZoomLevel(level: number): void {
protected async setConfiguredZoomLevel(level: number): Promise<void> {
level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels
const applyZoom = () => {
@@ -98,7 +98,9 @@ export abstract class BaseZoomAction extends Action {
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
};
this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level).then(() => applyZoom());
await this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level);
applyZoom();
}
}
@@ -175,8 +177,10 @@ export class ReloadWindowAction extends Action {
super(id, label);
}
run(): Promise<boolean> {
return this.windowService.reloadWindow().then(() => true);
async run(): Promise<boolean> {
await this.windowService.reloadWindow();
return true;
}
}
@@ -193,8 +197,10 @@ export class ReloadWindowWithExtensionsDisabledAction extends Action {
super(id, label);
}
run(): Promise<boolean> {
return this.windowService.reloadWindow({ _: [], 'disable-extensions': true }).then(() => true);
async run(): Promise<boolean> {
await this.windowService.reloadWindow({ _: [], 'disable-extensions': true });
return true;
}
}
@@ -221,41 +227,38 @@ export abstract class BaseSwitchWindow extends Action {
protected abstract isQuickNavigate(): boolean;
run(): Promise<void> {
async run(): Promise<void> {
const currentWindowId = this.windowService.windowId;
return this.windowsService.getWindows().then(windows => {
const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to");
const picks = windows.map(win => {
const resource = win.filename ? URI.file(win.filename) : win.folderUri ? win.folderUri : win.workspace ? win.workspace.configPath : undefined;
const fileKind = win.filename ? FileKind.FILE : win.workspace ? FileKind.ROOT_FOLDER : win.folderUri ? FileKind.FOLDER : FileKind.FILE;
return {
payload: win.id,
label: win.title,
iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind),
description: (currentWindowId === win.id) ? nls.localize('current', "Current Window") : undefined,
buttons: (!this.isQuickNavigate() && currentWindowId !== win.id) ? [this.closeWindowAction] : undefined
};
});
const windows = await this.windowsService.getWindows();
const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to");
const picks = windows.map(win => {
const resource = win.filename ? URI.file(win.filename) : win.folderUri ? win.folderUri : win.workspace ? win.workspace.configPath : undefined;
const fileKind = win.filename ? FileKind.FILE : win.workspace ? FileKind.ROOT_FOLDER : win.folderUri ? FileKind.FOLDER : FileKind.FILE;
return {
payload: win.id,
label: win.title,
iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind),
description: (currentWindowId === win.id) ? nls.localize('current', "Current Window") : undefined,
buttons: (!this.isQuickNavigate() && currentWindowId !== win.id) ? [this.closeWindowAction] : undefined
};
});
const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length;
const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length;
return this.quickInputService.pick(picks, {
contextKey: 'inWindowsPicker',
activeItem: picks[autoFocusIndex],
placeHolder,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
onDidTriggerItemButton: context => {
this.windowsService.closeWindow(context.item.payload).then(() => {
context.removeItem();
});
}
});
}).then(pick => {
if (pick) {
this.windowsService.focusWindow(pick.payload);
const pick = await this.quickInputService.pick(picks, {
contextKey: 'inWindowsPicker',
activeItem: picks[autoFocusIndex],
placeHolder,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
onDidTriggerItemButton: async context => {
await this.windowsService.closeWindow(context.item.payload);
context.removeItem();
}
});
if (pick) {
this.windowsService.focusWindow(pick.payload);
}
}
}
@@ -331,12 +334,13 @@ export abstract class BaseOpenRecentAction extends Action {
protected abstract isQuickNavigate(): boolean;
run(): Promise<void> {
return this.windowService.getRecentlyOpened()
.then(({ workspaces, files }) => this.openRecent(workspaces, files));
async run(): Promise<void> {
const { workspaces, files } = await this.windowService.getRecentlyOpened();
this.openRecent(workspaces, files);
}
private openRecent(recentWorkspaces: Array<IRecentWorkspace | IRecentFolder>, recentFiles: IRecentFile[]): void {
private async openRecent(recentWorkspaces: Array<IRecentWorkspace | IRecentFolder>, recentFiles: IRecentFile[]): Promise<void> {
const toPick = (recent: IRecent, labelService: ILabelService, buttons: IQuickInputButton[] | undefined) => {
let uriToOpen: IURIToOpen | undefined;
@@ -376,26 +380,26 @@ export abstract class BaseOpenRecentAction extends Action {
const firstEntry = recentWorkspaces[0];
let autoFocusSecondEntry: boolean = firstEntry && this.contextService.isCurrentWorkspace(isRecentWorkspace(firstEntry) ? firstEntry.workspace : firstEntry.folderUri);
let keyMods: IKeyMods;
let keyMods: IKeyMods | undefined;
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") };
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") };
const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks];
this.quickInputService.pick(picks, {
const pick = await this.quickInputService.pick(picks, {
contextKey: inRecentFilesPickerContextKey,
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to open in new window)"),
matchOnDescription: true,
onKeyMods: mods => keyMods = mods,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
onDidTriggerItemButton: context => {
this.windowsService.removeFromRecentlyOpened([context.item.resource]).then(() => context.removeItem());
}
}).then((pick): Promise<void> | void => {
if (pick) {
const forceNewWindow = keyMods.ctrlCmd;
return this.windowService.openWindow([pick.uriToOpen], { forceNewWindow });
onDidTriggerItemButton: async context => {
await this.windowsService.removeFromRecentlyOpened([context.item.resource]);
context.removeItem();
}
});
if (pick) {
return this.windowService.openWindow([pick.uriToOpen], { forceNewWindow: keyMods && keyMods.ctrlCmd });
}
}
}

View File

@@ -106,42 +106,39 @@ class CodeRendererMain extends Disposable {
}
}
open(): Promise<void> {
return this.initServices().then(services => {
async open(): Promise<void> {
const services = await this.initServices();
await domContentLoaded();
mark('willStartWorkbench');
return domContentLoaded().then(() => {
mark('willStartWorkbench');
// Create Workbench
this.workbench = new Workbench(document.body, services.serviceCollection, services.logService);
// Create Workbench
this.workbench = new Workbench(document.body, services.serviceCollection, services.logService);
// Layout
this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true)));
// Layout
this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true)));
// Workbench Lifecycle
this._register(this.workbench.onShutdown(() => this.dispose()));
this._register(this.workbench.onWillShutdown(event => event.join(services.storageService.close())));
// Workbench Lifecycle
this._register(this.workbench.onShutdown(() => this.dispose()));
this._register(this.workbench.onWillShutdown(event => event.join(services.storageService.close())));
// Startup
const instantiationService = this.workbench.startup();
// Startup
const instantiationService = this.workbench.startup();
// Window
this._register(instantiationService.createInstance(ElectronWindow));
// Window
this._register(instantiationService.createInstance(ElectronWindow));
// Driver
if (this.configuration.driver) {
instantiationService.invokeFunction(async accessor => this._register(await registerWindowDriver(accessor)));
}
// Driver
if (this.configuration.driver) {
instantiationService.invokeFunction(accessor => registerWindowDriver(accessor).then(disposable => this._register(disposable)));
}
// Config Exporter
if (this.configuration['export-default-configuration']) {
instantiationService.createInstance(DefaultConfigurationExportHelper);
}
// Config Exporter
if (this.configuration['export-default-configuration']) {
instantiationService.createInstance(DefaultConfigurationExportHelper);
}
// Logging
services.logService.trace('workbench configuration', JSON.stringify(this.configuration));
});
});
// Logging
services.logService.trace('workbench configuration', JSON.stringify(this.configuration));
}
private onWindowResize(e: Event, retry: boolean): void {
@@ -162,7 +159,7 @@ class CodeRendererMain extends Disposable {
}
}
private initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> {
private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> {
const serviceCollection = new ServiceCollection();
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -203,7 +200,9 @@ class CodeRendererMain extends Disposable {
fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider);
}
return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([
const payload = await this.resolveWorkspaceInitializationPayload(environmentService);
const services = await Promise.all([
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
// Workspace
@@ -222,10 +221,12 @@ class CodeRendererMain extends Disposable {
return service;
})
]).then(services => ({ serviceCollection, logService, storageService: services[1] })));
]);
return { serviceCollection, logService, storageService: services[1] };
}
private resolveWorkspaceInitializationPayload(environmentService: IWorkbenchEnvironmentService): Promise<IWorkspaceInitializationPayload> {
private async resolveWorkspaceInitializationPayload(environmentService: IWorkbenchEnvironmentService): Promise<IWorkspaceInitializationPayload> {
// Multi-root workspace
if (this.configuration.workspace) {
@@ -233,32 +234,29 @@ class CodeRendererMain extends Disposable {
}
// Single-folder workspace
let workspaceInitializationPayload: Promise<IWorkspaceInitializationPayload | undefined> = Promise.resolve(undefined);
let workspaceInitializationPayload: IWorkspaceInitializationPayload | undefined;
if (this.configuration.folderUri) {
workspaceInitializationPayload = this.resolveSingleFolderWorkspaceInitializationPayload(this.configuration.folderUri);
workspaceInitializationPayload = await this.resolveSingleFolderWorkspaceInitializationPayload(this.configuration.folderUri);
}
return workspaceInitializationPayload.then(payload => {
// Fallback to empty workspace if we have no payload yet.
if (!payload) {
let id: string;
if (this.configuration.backupPath) {
id = basename(this.configuration.backupPath); // we know the backupPath must be a unique path so we leverage its name as workspace ID
} else if (environmentService.isExtensionDevelopment) {
id = 'ext-dev'; // extension development window never stores backups and is a singleton
} else {
return Promise.reject(new Error('Unexpected window configuration without backupPath'));
}
payload = { id };
// Fallback to empty workspace if we have no payload yet.
if (!workspaceInitializationPayload) {
let id: string;
if (this.configuration.backupPath) {
id = basename(this.configuration.backupPath); // we know the backupPath must be a unique path so we leverage its name as workspace ID
} else if (environmentService.isExtensionDevelopment) {
id = 'ext-dev'; // extension development window never stores backups and is a singleton
} else {
throw new Error('Unexpected window configuration without backupPath');
}
return payload;
});
workspaceInitializationPayload = { id };
}
return workspaceInitializationPayload;
}
private resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier): Promise<ISingleFolderWorkspaceInitializationPayload | undefined> {
private async resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier): Promise<ISingleFolderWorkspaceInitializationPayload | undefined> {
// Return early the folder is not local
if (folderUri.scheme !== Schemas.file) {
@@ -285,40 +283,54 @@ class CodeRendererMain extends Disposable {
}
// For local: ensure path is absolute and exists
const sanitizedFolderPath = sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd());
return stat(sanitizedFolderPath).then(stat => {
try {
const sanitizedFolderPath = sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd());
const fileStat = await stat(sanitizedFolderPath);
const sanitizedFolderUri = URI.file(sanitizedFolderPath);
return {
id: computeLocalDiskFolderId(sanitizedFolderUri, stat),
id: computeLocalDiskFolderId(sanitizedFolderUri, fileStat),
folder: sanitizedFolderUri
};
}, error => onUnexpectedError(error));
} catch (error) {
onUnexpectedError(error);
}
return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check
}
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
const configurationFileService = new ConfigurationFileService();
configurationFileService.fileService = fileService;
const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService);
return workspaceService.initialize(payload).then(() => workspaceService, error => {
try {
await workspaceService.initialize(payload);
return workspaceService;
} catch (error) {
onUnexpectedError(error);
logService.error(error);
return workspaceService;
});
}
}
private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, logService: ILogService, mainProcessService: IMainProcessService): Promise<StorageService> {
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, logService: ILogService, mainProcessService: IMainProcessService): Promise<StorageService> {
const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage'));
const storageService = new StorageService(globalStorageDatabase, logService, environmentService);
return storageService.initialize(payload).then(() => storageService, error => {
try {
await storageService.initialize(payload);
return storageService;
} catch (error) {
onUnexpectedError(error);
logService.error(error);
return storageService;
});
}
}
private createLogService(mainProcessService: IMainProcessService, environmentService: IWorkbenchEnvironmentService): ILogService {

View File

@@ -117,7 +117,7 @@ export class ElectronWindow extends Disposable {
});
// Support runAction event
ipc.on('vscode:runAction', (event: Event, request: IRunActionInWindowRequest) => {
ipc.on('vscode:runAction', async (event: Event, request: IRunActionInWindowRequest) => {
const args: unknown[] = request.args || [];
// If we run an action from the touchbar, we fill in the currently active resource
@@ -134,7 +134,9 @@ export class ElectronWindow extends Disposable {
args.push({ from: request.from }); // TODO@telemetry this is a bit weird to send this to every action?
}
this.commandService.executeCommand(request.id, ...args).then(_ => {
try {
await this.commandService.executeCommand(request.id, ...args);
/* __GDPR__
"commandExecuted" : {
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
@@ -142,9 +144,9 @@ export class ElectronWindow extends Disposable {
}
*/
this.telemetryService.publicLog('commandExecuted', { id: request.id, from: request.from });
}, err => {
this.notificationService.error(err);
});
} catch (error) {
this.notificationService.error(error);
}
});
// Support runKeybinding event
@@ -173,34 +175,30 @@ export class ElectronWindow extends Disposable {
});
// Fullscreen Events
ipc.on('vscode:enterFullScreen', () => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
browser.setFullscreen(true);
});
ipc.on('vscode:enterFullScreen', async () => {
await this.lifecycleService.when(LifecyclePhase.Ready);
browser.setFullscreen(true);
});
ipc.on('vscode:leaveFullScreen', () => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
browser.setFullscreen(false);
});
ipc.on('vscode:leaveFullScreen', async () => {
await this.lifecycleService.when(LifecyclePhase.Ready);
browser.setFullscreen(false);
});
// High Contrast Events
ipc.on('vscode:enterHighContrast', () => {
ipc.on('vscode:enterHighContrast', async () => {
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
this.themeService.setColorTheme(VS_HC_THEME, undefined);
});
await this.lifecycleService.when(LifecyclePhase.Ready);
this.themeService.setColorTheme(VS_HC_THEME, undefined);
}
});
ipc.on('vscode:leaveHighContrast', () => {
ipc.on('vscode:leaveHighContrast', async () => {
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
this.themeService.restoreColorTheme();
});
await this.lifecycleService.when(LifecyclePhase.Ready);
this.themeService.restoreColorTheme();
}
});
@@ -310,32 +308,28 @@ export class ElectronWindow extends Disposable {
};
// Emit event when vscode is ready
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
ipc.send('vscode:workbenchReady', this.windowService.windowId);
});
this.lifecycleService.when(LifecyclePhase.Ready).then(() => ipc.send('vscode:workbenchReady', this.windowService.windowId));
// Integrity warning
this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure }));
// Root warning
this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
let isAdminPromise: Promise<boolean>;
this.lifecycleService.when(LifecyclePhase.Restored).then(async () => {
let isAdmin: boolean;
if (isWindows) {
isAdminPromise = import('native-is-elevated').then(isElevated => isElevated());
const isElevated = await import('native-is-elevated');
isAdmin = isElevated();
} else {
isAdminPromise = Promise.resolve(isRootUser());
isAdmin = isRootUser();
}
return isAdminPromise.then(isAdmin => {
// Update title
this.titleService.updateProperties({ isAdmin });
// Update title
this.titleService.updateProperties({ isAdmin });
// Show warning message (unix only)
if (isAdmin && !isWindows) {
this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort));
}
});
// Show warning message (unix only)
if (isAdmin && !isWindows) {
this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort));
}
});
// Touchbar menu (if enabled)
@@ -408,7 +402,7 @@ export class ElectronWindow extends Disposable {
}
}
private setupCrashReporter(): void {
private async setupCrashReporter(): Promise<void> {
// base options with product info
const options = {
@@ -422,18 +416,14 @@ export class ElectronWindow extends Disposable {
};
// mixin telemetry info
this.telemetryService.getTelemetryInfo()
.then(info => {
assign(options.extra, {
vscode_sessionId: info.sessionId
});
const info = await this.telemetryService.getTelemetryInfo();
assign(options.extra, { vscode_sessionId: info.sessionId });
// start crash reporter right here
crashReporter.start(deepClone(options));
// start crash reporter right here
crashReporter.start(deepClone(options));
// start crash reporter in the main process
return this.windowsService.startCrashReporter(options);
});
// start crash reporter in the main process
return this.windowsService.startCrashReporter(options);
}
private onAddFoldersRequest(request: IAddFoldersRequest): void {
@@ -525,22 +515,21 @@ export class ElectronWindow extends Disposable {
});
}
private openResources(resources: Array<IResourceInput | IUntitledResourceInput>, diffMode: boolean): void {
this.lifecycleService.when(LifecyclePhase.Ready).then((): Promise<unknown> => {
private async openResources(resources: Array<IResourceInput | IUntitledResourceInput>, diffMode: boolean): Promise<unknown> {
await this.lifecycleService.when(LifecyclePhase.Ready);
// In diffMode we open 2 resources as diff
if (diffMode && resources.length === 2) {
return this.editorService.openEditor({ leftResource: resources[0].resource!, rightResource: resources[1].resource!, options: { pinned: true } });
}
// In diffMode we open 2 resources as diff
if (diffMode && resources.length === 2) {
return this.editorService.openEditor({ leftResource: resources[0].resource!, rightResource: resources[1].resource!, options: { pinned: true } });
}
// For one file, just put it into the current active editor
if (resources.length === 1) {
return this.editorService.openEditor(resources[0]);
}
// For one file, just put it into the current active editor
if (resources.length === 1) {
return this.editorService.openEditor(resources[0]);
}
// Otherwise open all
return this.editorService.openEditors(resources);
});
// Otherwise open all
return this.editorService.openEditors(resources);
}
dispose(): void {