Skip to content

Commit 4247dde

Browse files
committed
perf - make window opening async and avoid sync disk access
1 parent 67d7705 commit 4247dde

File tree

12 files changed

+113
-215
lines changed

12 files changed

+113
-215
lines changed

src/vs/code/electron-main/app.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ import { IExtensionsScannerService } from 'vs/platform/extensionManagement/commo
109109
import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService';
110110
import { UserDataTransientProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataTransientProfilesHandler';
111111
import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
112-
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
113112

114113
/**
115114
* The main VS Code application. There will only ever be one instance,
@@ -326,12 +325,12 @@ export class CodeApplication extends Disposable {
326325
});
327326

328327
// macOS dock activate
329-
app.on('activate', (event, hasVisibleWindows) => {
328+
app.on('activate', async (event, hasVisibleWindows) => {
330329
this.logService.trace('app#activate');
331330

332331
// Mac only event: open new window when we get activated
333332
if (!hasVisibleWindows) {
334-
this.windowsMainService?.openEmptyWindow({ context: OpenContext.DOCK });
333+
await this.windowsMainService?.openEmptyWindow({ context: OpenContext.DOCK });
335334
}
336335
});
337336

@@ -372,8 +371,8 @@ export class CodeApplication extends Disposable {
372371
}
373372

374373
// Handle paths delayed in case more are coming!
375-
runningTimeout = setTimeout(() => {
376-
this.windowsMainService?.open({
374+
runningTimeout = setTimeout(async () => {
375+
await this.windowsMainService?.open({
377376
context: OpenContext.DOCK /* can also be opening from finder while app is running */,
378377
cli: this.environmentMainService.args,
379378
urisToOpen: macOpenFileURIs,
@@ -386,8 +385,8 @@ export class CodeApplication extends Disposable {
386385
}, 100);
387386
});
388387

389-
app.on('new-window-for-tab', () => {
390-
this.windowsMainService?.openEmptyWindow({ context: OpenContext.DESKTOP }); //macOS native tab "+" button
388+
app.on('new-window-for-tab', async () => {
389+
await this.windowsMainService?.openEmptyWindow({ context: OpenContext.DESKTOP }); //macOS native tab "+" button
391390
});
392391

393392
//#region Bootstrap IPC Handlers
@@ -537,15 +536,11 @@ export class CodeApplication extends Disposable {
537536
// Setup Handlers
538537
this.setUpHandlers(appInstantiationService);
539538

540-
// Ensure profile exists when passed in from CLI
541-
const profilePromise = this.userDataProfilesMainService.checkAndCreateProfileFromCli(this.environmentMainService.args);
542-
const profile = profilePromise ? await profilePromise : undefined;
543-
544539
// Init Channels
545540
appInstantiationService.invokeFunction(accessor => this.initChannels(accessor, mainProcessElectronServer, sharedProcessClient));
546541

547542
// Open Windows
548-
appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, profile, mainProcessElectronServer));
543+
await appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, mainProcessElectronServer));
549544

550545
// Post Open Windows Tasks
551546
appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor, sharedProcess));
@@ -834,7 +829,7 @@ export class CodeApplication extends Disposable {
834829
mainProcessElectronServer.registerChannel(ipcExtensionHostStarterChannelName, extensionHostStarterChannel);
835830
}
836831

837-
private openFirstWindow(accessor: ServicesAccessor, profile: IUserDataProfile | undefined, mainProcessElectronServer: ElectronIPCServer): ICodeWindow[] {
832+
private async openFirstWindow(accessor: ServicesAccessor, mainProcessElectronServer: ElectronIPCServer): Promise<ICodeWindow[]> {
838833
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
839834
const urlService = accessor.get(IURLService);
840835
const nativeHostMainService = accessor.get(INativeHostMainService);
@@ -922,7 +917,7 @@ export class CodeApplication extends Disposable {
922917
const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri);
923918
logService.trace('app#handleURL: windowOpenableFromProtocolLink = ', windowOpenableFromProtocolLink);
924919
if (windowOpenableFromProtocolLink) {
925-
const [window] = windowsMainService.open({
920+
const [window] = await windowsMainService.open({
926921
context: OpenContext.API,
927922
cli: { ...environmentService.args },
928923
urisToOpen: [windowOpenableFromProtocolLink],
@@ -937,7 +932,7 @@ export class CodeApplication extends Disposable {
937932
}
938933

939934
if (shouldOpenInNewWindow) {
940-
const [window] = windowsMainService.open({
935+
const [window] = await windowsMainService.open({
941936
context: OpenContext.API,
942937
cli: { ...environmentService.args },
943938
forceNewWindow: true,
@@ -994,6 +989,9 @@ export class CodeApplication extends Disposable {
994989
});
995990
}
996991

992+
// Ensure profile exists when passed in from CLI
993+
const profile = await this.userDataProfilesMainService.checkAndCreateProfileFromCli(this.environmentMainService.args);
994+
997995
// Start without file/folder arguments
998996
if (!hasCliArgs && !hasFolderURIs && !hasFileURIs) {
999997

src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,10 @@ export class ElectronExtensionHostDebugBroadcastChannel<TContext> extends Extens
3636
return { success: false };
3737
}
3838

39-
// Ensure profile exists when passed in from args
40-
const profilePromise = this.userDataProfilesMainService.checkAndCreateProfileFromCli(pargs);
41-
const profile = profilePromise ? await profilePromise : undefined;
42-
43-
const [codeWindow] = this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
39+
const [codeWindow] = await this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
4440
context: OpenContext.API,
4541
cli: pargs,
46-
profile
42+
profile: await this.userDataProfilesMainService.checkAndCreateProfileFromCli(pargs)
4743
});
4844

4945
if (!debugRenderer) {

src/vs/platform/launch/electron-main/launchMainService.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { app } from 'electron';
7-
import { coalesce } from 'vs/base/common/arrays';
7+
import { coalesce, firstOrDefault } from 'vs/base/common/arrays';
88
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
99
import { URI } from 'vs/base/common/uri';
1010
import { whenDeleted } from 'vs/base/node/pfs';
@@ -71,8 +71,10 @@ export class LaunchMainService implements ILaunchMainService {
7171

7272
// Create a window if there is none
7373
if (this.windowsMainService.getWindowCount() === 0) {
74-
const window = this.windowsMainService.openEmptyWindow({ context: OpenContext.DESKTOP })[0];
75-
whenWindowReady = window.ready();
74+
const window = firstOrDefault(await this.windowsMainService.openEmptyWindow({ context: OpenContext.DESKTOP }));
75+
if (window) {
76+
whenWindowReady = window.ready();
77+
}
7678
}
7779

7880
// Make sure a window is open, ready to receive the url event
@@ -116,8 +118,7 @@ export class LaunchMainService implements ILaunchMainService {
116118
const remoteAuthority = args.remote || undefined;
117119

118120
// Ensure profile exists when passed in from CLI
119-
const profilePromise = this.userDataProfilesMainService.checkAndCreateProfileFromCli(args);
120-
const profile = profilePromise ? await profilePromise : undefined;
121+
const profile = await this.userDataProfilesMainService.checkAndCreateProfileFromCli(args);
121122

122123
const baseConfig: IOpenConfiguration = {
123124
context,
@@ -130,7 +131,7 @@ export class LaunchMainService implements ILaunchMainService {
130131

131132
// Special case extension development
132133
if (!!args.extensionDevelopmentPath) {
133-
this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, baseConfig);
134+
await this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, baseConfig);
134135
}
135136

136137
// Start without file/folder arguments
@@ -165,7 +166,7 @@ export class LaunchMainService implements ILaunchMainService {
165166

166167
// Open new Window
167168
if (openNewWindow) {
168-
usedWindows = this.windowsMainService.open({
169+
usedWindows = await this.windowsMainService.open({
169170
...baseConfig,
170171
forceNewWindow: true,
171172
forceEmpty: true
@@ -180,7 +181,7 @@ export class LaunchMainService implements ILaunchMainService {
180181

181182
usedWindows = [lastActive];
182183
} else {
183-
usedWindows = this.windowsMainService.open({
184+
usedWindows = await this.windowsMainService.open({
184185
...baseConfig,
185186
forceEmpty: true
186187
});
@@ -190,7 +191,7 @@ export class LaunchMainService implements ILaunchMainService {
190191

191192
// Start with file/folder arguments
192193
else {
193-
usedWindows = this.windowsMainService.open({
194+
usedWindows = await this.windowsMainService.open({
194195
...baseConfig,
195196
forceNewWindow: args['new-window'],
196197
preferNewWindow: !args['reuse-window'] && !args.wait,

src/vs/platform/menubar/electron-main/menubar.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -532,19 +532,19 @@ export class Menubar {
532532

533533
return new MenuItem(this.likeAction(commandId, {
534534
label: item.label,
535-
click: (menuItem, win, event) => {
535+
click: async (menuItem, win, event) => {
536536
const openInNewWindow = this.isOptionClick(event);
537-
const success = this.windowsMainService.open({
537+
const success = (await this.windowsMainService.open({
538538
context: OpenContext.MENU,
539539
cli: this.environmentMainService.args,
540540
urisToOpen: [openable],
541541
forceNewWindow: openInNewWindow,
542542
gotoLineMode: false,
543543
remoteAuthority: item.remoteAuthority
544-
}).length > 0;
544+
})).length > 0;
545545

546546
if (!success) {
547-
this.workspacesHistoryMainService.removeRecentlyOpened([revivedUri]);
547+
await this.workspacesHistoryMainService.removeRecentlyOpened([revivedUri]);
548548
}
549549
}
550550
}, false));

src/vs/platform/native/electron-main/nativeHostMainService.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
146146

147147
private async doOpenWindow(windowId: number | undefined, toOpen: IWindowOpenable[], options: IOpenWindowOptions = Object.create(null)): Promise<void> {
148148
if (toOpen.length > 0) {
149-
this.windowsMainService.open({
149+
await this.windowsMainService.open({
150150
context: OpenContext.API,
151151
contextWindowId: windowId,
152152
urisToOpen: toOpen,
@@ -166,7 +166,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
166166
}
167167

168168
private async doOpenEmptyWindow(windowId: number | undefined, options?: IOpenEmptyWindowOptions): Promise<void> {
169-
this.windowsMainService.openEmptyWindow({
169+
await this.windowsMainService.openEmptyWindow({
170170
context: OpenContext.API,
171171
contextWindowId: windowId
172172
}, options);
@@ -384,33 +384,33 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
384384
async pickFileFolderAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise<void> {
385385
const paths = await this.dialogMainService.pickFileFolder(options);
386386
if (paths) {
387-
this.doOpenPicked(await Promise.all(paths.map(async path => (await SymlinkSupport.existsDirectory(path)) ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) })), options, windowId);
387+
await this.doOpenPicked(await Promise.all(paths.map(async path => (await SymlinkSupport.existsDirectory(path)) ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) })), options, windowId);
388388
}
389389
}
390390

391391
async pickFolderAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise<void> {
392392
const paths = await this.dialogMainService.pickFolder(options);
393393
if (paths) {
394-
this.doOpenPicked(paths.map(path => ({ folderUri: URI.file(path) })), options, windowId);
394+
await this.doOpenPicked(paths.map(path => ({ folderUri: URI.file(path) })), options, windowId);
395395
}
396396
}
397397

398398
async pickFileAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise<void> {
399399
const paths = await this.dialogMainService.pickFile(options);
400400
if (paths) {
401-
this.doOpenPicked(paths.map(path => ({ fileUri: URI.file(path) })), options, windowId);
401+
await this.doOpenPicked(paths.map(path => ({ fileUri: URI.file(path) })), options, windowId);
402402
}
403403
}
404404

405405
async pickWorkspaceAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise<void> {
406406
const paths = await this.dialogMainService.pickWorkspace(options);
407407
if (paths) {
408-
this.doOpenPicked(paths.map(path => ({ workspaceUri: URI.file(path) })), options, windowId);
408+
await this.doOpenPicked(paths.map(path => ({ workspaceUri: URI.file(path) })), options, windowId);
409409
}
410410
}
411411

412-
private doOpenPicked(openable: IWindowOpenable[], options: INativeOpenDialogOptions, windowId: number | undefined): void {
413-
this.windowsMainService.open({
412+
private async doOpenPicked(openable: IWindowOpenable[], options: INativeOpenDialogOptions, windowId: number | undefined): Promise<void> {
413+
await this.windowsMainService.open({
414414
context: OpenContext.DIALOG,
415415
contextWindowId: windowId,
416416
cli: this.environmentMainService.args,
@@ -623,7 +623,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
623623
//#region macOS Touchbar
624624

625625
async newWindowTab(): Promise<void> {
626-
this.windowsMainService.open({
626+
await this.windowsMainService.open({
627627
context: OpenContext.API,
628628
cli: this.environmentMainService.args,
629629
forceNewTabbedWindow: true,

src/vs/platform/windows/electron-main/windowImpl.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
666666
// shutdown as much as possible by destroying the window
667667
// and then calling the normal `quit` routine.
668668
if (this.environmentMainService.args['enable-smoke-test-driver']) {
669-
this.destroyWindow(false, false);
669+
await this.destroyWindow(false, false);
670670
this.lifecycleMainService.quit(); // still allow for an orderly shutdown
671671
return;
672672
}
@@ -703,7 +703,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
703703
// Handle choice
704704
if (result.response !== 1 /* keep waiting */) {
705705
const reopen = result.response === 0;
706-
this.destroyWindow(reopen, result.checkboxChecked);
706+
await this.destroyWindow(reopen, result.checkboxChecked);
707707
}
708708
}
709709

@@ -733,7 +733,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
733733

734734
// Handle choice
735735
const reopen = result.response === 0;
736-
this.destroyWindow(reopen, result.checkboxChecked);
736+
await this.destroyWindow(reopen, result.checkboxChecked);
737737
}
738738
break;
739739
}
@@ -775,7 +775,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
775775
}
776776

777777
// Delegate to windows service
778-
const [window] = this.windowsMainService.open({
778+
const [window] = await this.windowsMainService.open({
779779
context: OpenContext.API,
780780
userEnv: this._config.userEnv,
781781
cli: {

src/vs/platform/windows/electron-main/windows.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ export interface IWindowsMainService {
2626
readonly onDidTriggerSystemContextMenu: Event<{ window: ICodeWindow; x: number; y: number }>;
2727
readonly onDidDestroyWindow: Event<ICodeWindow>;
2828

29-
open(openConfig: IOpenConfiguration): ICodeWindow[];
30-
openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): ICodeWindow[];
29+
open(openConfig: IOpenConfiguration): Promise<ICodeWindow[]>;
30+
openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): Promise<ICodeWindow[]>;
31+
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): Promise<ICodeWindow[]>;
32+
3133
openExistingWindow(window: ICodeWindow, openConfig: IOpenConfiguration): void;
32-
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[];
3334

3435
sendToFocused(channel: string, ...args: any[]): void;
3536
sendToAll(channel: string, payload?: any, windowIdsToIgnore?: number[]): void;

src/vs/platform/windows/electron-main/windowsFinder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import { URI } from 'vs/base/common/uri';
88
import { ICodeWindow } from 'vs/platform/window/electron-main/window';
99
import { IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
1010

11-
export function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | undefined): ICodeWindow | undefined {
11+
export async function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => Promise<IResolvedWorkspace | undefined>): Promise<ICodeWindow | undefined> {
1212

1313
// First check for windows with workspaces that have a parent folder of the provided path opened
1414
for (const window of windows) {
1515
const workspace = window.openedWorkspace;
1616
if (isWorkspaceIdentifier(workspace)) {
17-
const resolvedWorkspace = localWorkspaceResolver(workspace);
17+
const resolvedWorkspace = await localWorkspaceResolver(workspace);
1818

1919
// resolved workspace: folders are known and can be compared with
2020
if (resolvedWorkspace) {

0 commit comments

Comments
 (0)