relauncher.contribution.ts 9.7 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
7
import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
8
import { Registry } from 'vs/platform/registry/common/platform';
9
import { IWindowsConfiguration } from 'vs/platform/windows/common/windows';
10
import { IHostService } from 'vs/workbench/services/host/browser/host';
11 12 13
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { localize } from 'vs/nls';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
14
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
15
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
16
import { RunOnceScheduler } from 'vs/base/common/async';
17
import { URI } from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
18
import { isEqual } from 'vs/base/common/resources';
B
Benjamin Pasero 已提交
19
import { isMacintosh, isNative } from 'vs/base/common/platform';
20
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
21
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
22
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
23

24
interface IConfiguration extends IWindowsConfiguration {
25
	update: { mode: string; };
26
	telemetry: { enableCrashReporter: boolean };
27
	workbench: { list: { horizontalScrolling: boolean } };
I
isidor 已提交
28
	debug: { console: { wordWrap: boolean } };
S
Sandeep Somavarapu 已提交
29
	configurationSync: { enableAuth: boolean };
30 31
}

B
Benjamin Pasero 已提交
32
export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution {
33

B
Benjamin Pasero 已提交
34 35 36 37 38 39 40 41
	private titleBarStyle: 'native' | 'custom' | undefined;
	private nativeTabs: boolean | undefined;
	private nativeFullScreen: boolean | undefined;
	private clickThroughInactive: boolean | undefined;
	private updateMode: string | undefined;
	private enableCrashReporter: boolean | undefined;
	private treeHorizontalScrolling: boolean | undefined;
	private debugConsoleWordWrap: boolean | undefined;
S
Sandeep Somavarapu 已提交
42
	private enableConfigSyncAuth: boolean | undefined;
43

44
	constructor(
45
		@IHostService private readonly hostService: IHostService,
46 47
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IEnvironmentService private readonly envService: IEnvironmentService,
48
		@IDialogService private readonly dialogService: IDialogService
49
	) {
B
Benjamin Pasero 已提交
50 51
		super();

52
		this.onConfigurationChange(configurationService.getValue<IConfiguration>(), false);
B
Benjamin Pasero 已提交
53
		this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getValue<IConfiguration>(), true)));
54 55 56 57 58
	}

	private onConfigurationChange(config: IConfiguration, notify: boolean): void {
		let changed = false;

59
		// Tree horizontal scrolling support
J
Joao Moreno 已提交
60 61
		if (config.workbench && config.workbench.list && typeof config.workbench.list.horizontalScrolling === 'boolean' && config.workbench.list.horizontalScrolling !== this.treeHorizontalScrolling) {
			this.treeHorizontalScrolling = config.workbench.list.horizontalScrolling;
62 63 64
			changed = true;
		}

I
isidor 已提交
65 66 67 68 69 70
		// Debug console word wrap
		if (config.debug && typeof config.debug.console.wordWrap === 'boolean' && config.debug.console.wordWrap !== this.debugConsoleWordWrap) {
			this.debugConsoleWordWrap = config.debug.console.wordWrap;
			changed = true;
		}

B
Benjamin Pasero 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
		if (isNative) {

			// Titlebar style
			if (config.window && config.window.titleBarStyle !== this.titleBarStyle && (config.window.titleBarStyle === 'native' || config.window.titleBarStyle === 'custom')) {
				this.titleBarStyle = config.window.titleBarStyle;
				changed = true;
			}

			// macOS: Native tabs
			if (isMacintosh && config.window && typeof config.window.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) {
				this.nativeTabs = config.window.nativeTabs;
				changed = true;
			}

			// macOS: Native fullscreen
			if (isMacintosh && config.window && typeof config.window.nativeFullScreen === 'boolean' && config.window.nativeFullScreen !== this.nativeFullScreen) {
				this.nativeFullScreen = config.window.nativeFullScreen;
				changed = true;
			}

			// macOS: Click through (accept first mouse)
			if (isMacintosh && config.window && typeof config.window.clickThroughInactive === 'boolean' && config.window.clickThroughInactive !== this.clickThroughInactive) {
				this.clickThroughInactive = config.window.clickThroughInactive;
				changed = true;
			}

			// Update channel
			if (config.update && typeof config.update.mode === 'string' && config.update.mode !== this.updateMode) {
				this.updateMode = config.update.mode;
				changed = true;
			}

			// Crash reporter
			if (config.telemetry && typeof config.telemetry.enableCrashReporter === 'boolean' && config.telemetry.enableCrashReporter !== this.enableCrashReporter) {
				this.enableCrashReporter = config.telemetry.enableCrashReporter;
				changed = true;
			}
		}

S
Sandeep Somavarapu 已提交
110 111 112 113 114 115
		// Configuration Sync Auth
		if (config.configurationSync && typeof config.configurationSync.enableAuth === 'boolean' && config.configurationSync.enableAuth !== this.enableConfigSyncAuth) {
			this.enableConfigSyncAuth = config.configurationSync.enableAuth;
			changed = true;
		}

116 117
		// Notify only when changed and we are the focused window (avoids notification spam across windows)
		if (notify && changed) {
118
			this.doConfirm(
B
Benjamin Pasero 已提交
119 120 121 122 123 124 125 126 127
				isNative ?
					localize('relaunchSettingMessage', "A setting has changed that requires a restart to take effect.") :
					localize('relaunchSettingMessageWeb', "A setting has changed that requires a reload to take effect."),
				isNative ?
					localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.envService.appNameLong) :
					localize('relaunchSettingDetailWeb', "Press the reload button to reload {0} and enable the setting.", this.envService.appNameLong),
				isNative ?
					localize('restart', "&&Restart") :
					localize('restartWeb', "&&Reload"),
128
				() => this.hostService.restart()
129 130 131 132
			);
		}
	}

133
	private doConfirm(message: string, detail: string, primaryButton: string, confirmed: () => void): void {
134 135 136 137 138 139 140 141 142 143 144 145
		if (this.hostService.hasFocus) {
			this.dialogService.confirm({
				type: 'info',
				message,
				detail,
				primaryButton
			}).then(res => {
				if (res.confirmed) {
					confirmed();
				}
			});
		}
146 147 148 149 150 151 152 153
	}
}

export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWorkbenchContribution {

	private firstFolderResource?: URI;
	private extensionHostRestarter: RunOnceScheduler;

B
Benjamin Pasero 已提交
154
	private onDidChangeWorkspaceFoldersUnbind: IDisposable | undefined;
155 156 157

	constructor(
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
M
Martin Aeschlimann 已提交
158
		@IExtensionService extensionService: IExtensionService,
159
		@IHostService hostService: IHostService,
160
		@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
161 162 163
	) {
		super();

M
Martin Aeschlimann 已提交
164
		this.extensionHostRestarter = this._register(new RunOnceScheduler(() => {
165 166 167
			if (!!environmentService.extensionTestsLocationURI) {
				return; // no restart when in tests: see https://github.com/Microsoft/vscode/issues/66936
			}
168

169
			if (environmentService.configuration.remoteAuthority) {
170
				hostService.reload(); // TODO@aeschli, workaround
171
			} else if (isNative) {
M
Martin Aeschlimann 已提交
172 173 174
				extensionService.restartExtensionHost();
			}
		}, 10));
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

		this.contextService.getCompleteWorkspace()
			.then(workspace => {
				this.firstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : undefined;
				this.handleWorkbenchState();
				this._register(this.contextService.onDidChangeWorkbenchState(() => setTimeout(() => this.handleWorkbenchState())));
			});

		this._register(toDisposable(() => {
			if (this.onDidChangeWorkspaceFoldersUnbind) {
				this.onDidChangeWorkspaceFoldersUnbind.dispose();
			}
		}));
	}

190 191 192 193
	private handleWorkbenchState(): void {

		// React to folder changes when we are in workspace state
		if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
194 195 196

			// Update our known first folder path if we entered workspace
			const workspace = this.contextService.getWorkspace();
R
Rob Lourens 已提交
197
			this.firstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : undefined;
198 199

			// Install workspace folder listener
200
			if (!this.onDidChangeWorkspaceFoldersUnbind) {
201
				this.onDidChangeWorkspaceFoldersUnbind = this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders());
202 203 204 205 206
			}
		}

		// Ignore the workspace folder changes in EMPTY or FOLDER state
		else {
B
Benjamin Pasero 已提交
207 208
			dispose(this.onDidChangeWorkspaceFoldersUnbind);
			this.onDidChangeWorkspaceFoldersUnbind = undefined;
209 210 211
		}
	}

S
Sandeep Somavarapu 已提交
212
	private onDidChangeWorkspaceFolders(): void {
213 214
		const workspace = this.contextService.getWorkspace();

215
		// Restart extension host if first root folder changed (impact on deprecated workspace.rootPath API)
R
Rob Lourens 已提交
216
		const newFirstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : undefined;
217
		if (!isEqual(this.firstFolderResource, newFirstFolderResource)) {
B
Benjamin Pasero 已提交
218
			this.firstFolderResource = newFirstFolderResource;
219

220
			this.extensionHostRestarter.schedule(); // buffer calls to extension host restart
221
		}
222
	}
223 224
}

225
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
B
Benjamin Pasero 已提交
226
workbenchRegistry.registerWorkbenchContribution(SettingsChangeRelauncher, LifecyclePhase.Restored);
227
workbenchRegistry.registerWorkbenchContribution(WorkspaceChangeExtHostRelauncher, LifecyclePhase.Restored);