main.ts 8.3 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

8
import nls = require('vs/nls');
J
Johannes Rieken 已提交
9 10 11
import { TPromise } from 'vs/base/common/winjs.base';
import { WorkbenchShell } from 'vs/workbench/electron-browser/shell';
import { IOptions } from 'vs/workbench/common/options';
12
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
13
import { domContentLoaded } from 'vs/base/browser/dom';
E
Erich Gamma 已提交
14
import errors = require('vs/base/common/errors');
15
import comparer = require('vs/base/common/comparers');
E
Erich Gamma 已提交
16 17 18 19
import platform = require('vs/base/common/platform');
import paths = require('vs/base/common/paths');
import uri from 'vs/base/common/uri';
import strings = require('vs/base/common/strings');
J
Johannes Rieken 已提交
20
import { IResourceInput } from 'vs/platform/editor/common/editor';
B
Benjamin Pasero 已提交
21
import { Workspace as LegacyWorkspace } from "vs/platform/workspace/common/workspace";
22
import { WorkspaceConfigurationService } from 'vs/workbench/services/configuration/node/configuration';
B
Benjamin Pasero 已提交
23
import { realpath, stat } from 'vs/base/node/pfs';
J
Johannes Rieken 已提交
24
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
E
Erich Gamma 已提交
25 26
import path = require('path');
import gracefulFs = require('graceful-fs');
B
Benjamin Pasero 已提交
27 28
import { IInitData } from 'vs/workbench/services/timer/common/timerService';
import { TimerService } from 'vs/workbench/services/timer/node/timerService';
A
Alex Dima 已提交
29
import { KeyboardMapperFactory } from "vs/workbench/services/keybinding/electron-browser/keybindingService";
30
import { IWindowConfiguration, IPath } from "vs/platform/windows/common/windows";
31 32 33
import { IStorageService } from "vs/platform/storage/common/storage";
import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { StorageService, inMemoryLocalStorageInstance, IWorkspaceStorageIdentifier } from "vs/platform/storage/common/storageService";
B
Benjamin Pasero 已提交
34

35 36
import { webFrame } from 'electron';

B
Benjamin Pasero 已提交
37
import fs = require('fs');
B
Benjamin Pasero 已提交
38
gracefulFs.gracefulify(fs); // enable gracefulFs
E
Erich Gamma 已提交
39

40
export function startup(configuration: IWindowConfiguration): TPromise<void> {
41

42 43
	// Ensure others can listen to zoom level changes
	browser.setZoomFactor(webFrame.getZoomFactor());
44

45 46
	// See https://github.com/Microsoft/vscode/issues/26151
	// Can be trusted because we are not setting it ourselves.
47
	browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */);
48

49 50
	browser.setFullscreen(!!configuration.fullscreen);

A
Alex Dima 已提交
51 52
	KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(configuration.isISOKeyboard);

53
	browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
54

55 56 57
	// Setup Intl
	comparer.setFileNameComparer(new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }));

E
Erich Gamma 已提交
58
	// Shell Options
B
polish  
Benjamin Pasero 已提交
59 60 61
	const filesToOpen = configuration.filesToOpen && configuration.filesToOpen.length ? toInputs(configuration.filesToOpen) : null;
	const filesToCreate = configuration.filesToCreate && configuration.filesToCreate.length ? toInputs(configuration.filesToCreate) : null;
	const filesToDiff = configuration.filesToDiff && configuration.filesToDiff.length ? toInputs(configuration.filesToDiff) : null;
B
Benjamin Pasero 已提交
62
	const shellOptions: IOptions = {
63 64
		filesToOpen,
		filesToCreate,
B
Benjamin Pasero 已提交
65
		filesToDiff
E
Erich Gamma 已提交
66 67
	};

68 69
	// Open workbench
	return openWorkbench(configuration, shellOptions);
E
Erich Gamma 已提交
70 71
}

72
function toInputs(paths: IPath[], isUntitledFile?: boolean): IResourceInput[] {
E
Erich Gamma 已提交
73
	return paths.map(p => {
74 75 76 77 78 79 80
		const input = <IResourceInput>{};

		if (isUntitledFile) {
			input.resource = uri.from({ scheme: 'untitled', path: p.filePath });
		} else {
			input.resource = uri.file(p.filePath);
		}
E
Erich Gamma 已提交
81

82 83 84 85
		input.options = {
			pinned: true // opening on startup is always pinned and not preview
		};

E
Erich Gamma 已提交
86
		if (p.lineNumber) {
87 88 89
			input.options.selection = {
				startLineNumber: p.lineNumber,
				startColumn: p.columnNumber
E
Erich Gamma 已提交
90 91 92 93 94 95 96
			};
		}

		return input;
	});
}

97
function openWorkbench(configuration: IWindowConfiguration, options: IOptions): TPromise<void> {
B
Benjamin Pasero 已提交
98
	return resolveLegacyWorkspace(configuration).then(legacyWorkspace => {
99
		const environmentService = new EnvironmentService(configuration, configuration.execPath);
B
Benjamin Pasero 已提交
100
		const workspaceConfigurationService = new WorkspaceConfigurationService(environmentService, legacyWorkspace);
101
		const timerService = new TimerService((<any>window).MonacoEnvironment.timers as IInitData, !!legacyWorkspace);
B
Benjamin Pasero 已提交
102
		const storageService = createStorageService(legacyWorkspace, configuration, environmentService);
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

		// Since the configuration service is one of the core services that is used in so many places, we initialize it
		// right before startup of the workbench shell to have its data ready for consumers
		return workspaceConfigurationService.initialize().then(() => {
			timerService.beforeDOMContentLoaded = Date.now();

			return domContentLoaded().then(() => {
				timerService.afterDOMContentLoaded = Date.now();

				// Open Shell
				timerService.beforeWorkbenchOpen = Date.now();
				const shell = new WorkbenchShell(document.body, {
					contextService: workspaceConfigurationService,
					configurationService: workspaceConfigurationService,
					environmentService,
					timerService,
					storageService
				}, configuration, options);
				shell.open();

				// Inform user about loading issues from the loader
				(<any>self).require.config({
					onError: (err: any) => {
						if (err.errorCode === 'load') {
							shell.onUnexpectedError(loaderError(err));
128
						}
129
					}
130 131 132 133 134 135
				});
			});
		});
	});
}

B
Benjamin Pasero 已提交
136
function resolveLegacyWorkspace(configuration: IWindowConfiguration): TPromise<LegacyWorkspace> {
137
	if (!configuration.workspacePath) {
138
		return TPromise.as(null);
E
Erich Gamma 已提交
139 140
	}

141
	return realpath(configuration.workspacePath).then(realWorkspacePath => {
142

E
Erich Gamma 已提交
143 144 145 146
		// for some weird reason, node adds a trailing slash to UNC paths
		// we never ever want trailing slashes as our workspace path unless
		// someone opens root ("/").
		// See also https://github.com/nodejs/io.js/issues/1765
147 148 149
		if (paths.isUNC(realWorkspacePath) && strings.endsWith(realWorkspacePath, paths.nativeSep)) {
			realWorkspacePath = strings.rtrim(realWorkspacePath, paths.nativeSep);
		}
E
Erich Gamma 已提交
150

151 152 153
		// update config
		configuration.workspacePath = realWorkspacePath;

154
		// resolve ctime of workspace
B
Benjamin Pasero 已提交
155
		return stat(realWorkspacePath).then(folderStat => new LegacyWorkspace(
156 157 158
			uri.file(realWorkspacePath),
			platform.isLinux ? folderStat.ino : folderStat.birthtime.getTime() // On Linux, birthtime is ctime, so we cannot use it! We use the ino instead!
		));
159
	}, error => {
160 161 162 163
		errors.onUnexpectedError(error);

		return null; // treat invalid paths as empty workspace
	});
E
Erich Gamma 已提交
164 165
}

B
Benjamin Pasero 已提交
166
function createStorageService(workspace: LegacyWorkspace, configuration: IWindowConfiguration, environmentService: IEnvironmentService): IStorageService {
167 168 169 170 171 172 173 174 175 176 177
	let id: IWorkspaceStorageIdentifier;
	if (workspace) {
		id = { resource: workspace.resource, uid: workspace.ctime };
	} else if (configuration.backupPath) {
		// if we do not have a workspace open, we need to find another identifier for the window to store
		// workspace UI state. if we have a backup path in the configuration we can use that because this
		// will be a unique identifier per window that is stable between restarts as long as there are
		// dirty files in the workspace.
		// We use basename() to produce a short identifier, we do not need the full path. We use a custom
		// scheme so that we can later distinguish these identifiers from the workspace one.
		id = { resource: uri.from({ path: path.basename(configuration.backupPath), scheme: 'empty' }) };
178 179
	}

180 181
	const disableStorage = !!environmentService.extensionTestsPath; // never keep any state when running extension tests!
	const storage = disableStorage ? inMemoryLocalStorageInstance : window.localStorage;
182

183
	return new StorageService(storage, storage, id);
184 185 186 187 188 189 190 191
}

function loaderError(err: Error): Error {
	if (platform.isWeb) {
		return new Error(nls.localize('loaderError', "Failed to load a required file. Either you are no longer connected to the internet or the server you are connected to is offline. Please refresh the browser to try again."));
	}

	return new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err)));
192
}