preferencesService.ts 27.3 KB
Newer Older
1 2 3 4
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
S
Sandeep Somavarapu 已提交
5

6 7 8
import { Emitter } from 'vs/base/common/event';
import { parse } from 'vs/base/common/json';
import { Disposable } from 'vs/base/common/lifecycle';
9
import * as network from 'vs/base/common/network';
10 11 12 13 14 15 16 17 18 19
import { assign } from 'vs/base/common/objects';
import * as strings from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { getCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
20
import * as nls from 'vs/nls';
21
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
B
Benjamin Pasero 已提交
22
import { IEditorOptions } from 'vs/platform/editor/common/editor';
23
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
24 25
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
26
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
27
import { ILabelService } from 'vs/platform/label/common/label';
28
import { INotificationService } from 'vs/platform/notification/common/notification';
29 30 31 32 33
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { EditorInput, IEditor } from 'vs/workbench/common/editor';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
B
Benjamin Pasero 已提交
34
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
35 36 37 38
import { GroupDirection, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { DEFAULT_SETTINGS_EDITOR_SETTING, FOLDER_SETTINGS_PATH, getSettingsTargetName, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorOptions, SettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
import { defaultKeybindingsContents, DefaultKeybindingsEditorModel, DefaultSettings, DefaultSettingsEditorModel, Settings2EditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
39

S
Sandeep Somavarapu 已提交
40 41
const emptyEditableSettingsContent = '{\n}';

42
export class PreferencesService extends Disposable implements IPreferencesService {
43 44

	_serviceBrand: any;
45

46
	private lastOpenedSettingsInput: PreferencesEditorInput | null = null;
47

M
Matt Bierner 已提交
48
	private readonly _onDispose: Emitter<void> = new Emitter<void>();
49

S
Sandeep Somavarapu 已提交
50 51 52 53 54 55
	private _defaultUserSettingsUriCounter = 0;
	private _defaultUserSettingsContentModel: DefaultSettings;
	private _defaultWorkspaceSettingsUriCounter = 0;
	private _defaultWorkspaceSettingsContentModel: DefaultSettings;
	private _defaultFolderSettingsUriCounter = 0;
	private _defaultFolderSettingsContentModel: DefaultSettings;
R
Rob Lourens 已提交
56

57
	constructor(
58 59
		@IEditorService private editorService: IEditorService,
		@IEditorGroupsService private editorGroupService: IEditorGroupsService,
60 61
		@IFileService private fileService: IFileService,
		@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
62
		@INotificationService private notificationService: INotificationService,
63 64 65
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IEnvironmentService private environmentService: IEnvironmentService,
66
		@ITelemetryService private telemetryService: ITelemetryService,
67
		@ITextModelService private textModelResolverService: ITextModelService,
68
		@IKeybindingService keybindingService: IKeybindingService,
69
		@IModelService private modelService: IModelService,
70
		@IJSONEditingService private jsonEditingService: IJSONEditingService,
I
isidor 已提交
71
		@IModeService private modeService: IModeService,
I
isidor 已提交
72
		@ILabelService private labelService: ILabelService
73 74
	) {
		super();
75 76 77 78 79 80 81 82
		// The default keybindings.json updates based on keyboard layouts, so here we make sure
		// if a model has been given out we update it accordingly.
		keybindingService.onDidUpdateKeybindings(() => {
			const model = modelService.getModel(this.defaultKeybindingsResource);
			if (!model) {
				// model has not been given out => nothing to do
				return;
			}
83
			modelService.updateModel(model, defaultKeybindingsContents(keybindingService));
84
		});
85 86
	}

S
Sandeep Somavarapu 已提交
87
	readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' });
S
Sandeep Somavarapu 已提交
88
	private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' });
89

90 91 92 93 94 95 96 97
	get userSettingsResource(): URI {
		return this.getEditableSettingsURI(ConfigurationTarget.USER);
	}

	get workspaceSettingsResource(): URI {
		return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
	}

98 99 100 101
	get settingsEditor2Input(): SettingsEditor2Input {
		return this.instantiationService.createInstance(SettingsEditor2Input);
	}

S
Sandeep Somavarapu 已提交
102
	getFolderSettingsResource(resource: URI): URI {
103
		return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource);
S
Sandeep Somavarapu 已提交
104 105
	}

J
Johannes Rieken 已提交
106
	resolveModel(uri: URI): Promise<ITextModel> {
S
Sandeep Somavarapu 已提交
107
		if (this.isDefaultSettingsResource(uri)) {
S
Sandeep Somavarapu 已提交
108

S
Sandeep Somavarapu 已提交
109
			const target = this.getConfigurationTargetFromDefaultSettingsResource(uri);
A
Alex Dima 已提交
110 111
			const languageSelection = this.modeService.create('jsonc');
			const model = this._register(this.modelService.createModel('', languageSelection, uri));
S
Sandeep Somavarapu 已提交
112 113 114 115 116 117 118 119 120

			let defaultSettings: DefaultSettings;
			this.configurationService.onDidChangeConfiguration(e => {
				if (e.source === ConfigurationTarget.DEFAULT) {
					const model = this.modelService.getModel(uri);
					if (!model) {
						// model has not been given out => nothing to do
						return;
					}
S
Sandeep Somavarapu 已提交
121
					defaultSettings = this.getDefaultSettings(target);
122
					this.modelService.updateModel(model, defaultSettings.getContent(true));
123
					defaultSettings._onDidChange.fire();
S
Sandeep Somavarapu 已提交
124 125 126 127 128
				}
			});

			// Check if Default settings is already created and updated in above promise
			if (!defaultSettings) {
S
Sandeep Somavarapu 已提交
129
				defaultSettings = this.getDefaultSettings(target);
130
				this.modelService.updateModel(model, defaultSettings.getContent(true));
S
Sandeep Somavarapu 已提交
131 132
			}

R
Rob Lourens 已提交
133
			return Promise.resolve(model);
134 135
		}

S
Sandeep Somavarapu 已提交
136
		if (this.defaultSettingsRawResource.toString() === uri.toString()) {
S
Sandeep Somavarapu 已提交
137
			let defaultSettings: DefaultSettings = this.getDefaultSettings(ConfigurationTarget.USER);
A
Alex Dima 已提交
138 139
			const languageSelection = this.modeService.create('jsonc');
			const model = this._register(this.modelService.createModel(defaultSettings.raw, languageSelection, uri));
R
Rob Lourens 已提交
140
			return Promise.resolve(model);
S
Sandeep Somavarapu 已提交
141 142
		}

143
		if (this.defaultKeybindingsResource.toString() === uri.toString()) {
S
Sandeep Somavarapu 已提交
144
			const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri);
A
Alex Dima 已提交
145 146
			const languageSelection = this.modeService.create('jsonc');
			const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, languageSelection, uri));
R
Rob Lourens 已提交
147
			return Promise.resolve(model);
148 149
		}

R
Rob Lourens 已提交
150
		return Promise.resolve(null);
151 152
	}

J
Johannes Rieken 已提交
153
	createPreferencesEditorModel(uri: URI): Promise<IPreferencesEditorModel<any>> {
S
Sandeep Somavarapu 已提交
154
		if (this.isDefaultSettingsResource(uri)) {
155
			return this.createDefaultSettingsEditorModel(uri);
156 157
		}

158
		if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) {
159
			return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri);
160
		}
161

S
Sandeep Somavarapu 已提交
162
		const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
163
		if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) {
164
			return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri);
165
		}
166

167
		if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
168
			return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri);
169
		}
170

R
Rob Lourens 已提交
171
		return Promise.resolve<IPreferencesEditorModel<any>>(null);
172 173
	}

J
Johannes Rieken 已提交
174
	openRawDefaultSettings(): Promise<IEditor> {
B
Benjamin Pasero 已提交
175
		return this.editorService.openEditor({ resource: this.defaultSettingsRawResource });
S
Sandeep Somavarapu 已提交
176 177
	}

J
Johannes Rieken 已提交
178
	openRawUserSettings(): Promise<IEditor> {
179
		return this.editorService.openEditor({ resource: this.userSettingsResource });
S
Sandeep Somavarapu 已提交
180 181
	}

J
Johannes Rieken 已提交
182
	openSettings(jsonEditor?: boolean): Promise<IEditor> {
183 184 185 186
		jsonEditor = typeof jsonEditor === 'undefined' ?
			this.configurationService.getValue('workbench.settings.editor') === 'json' :
			jsonEditor;

187 188 189 190
		if (!jsonEditor) {
			return this.openSettings2();
		}

191 192
		const editorInput = this.getActiveSettingsEditorInput() || this.lastOpenedSettingsInput;
		const resource = editorInput ? editorInput.master.getResource() : this.userSettingsResource;
S
Sandeep Somavarapu 已提交
193
		const target = this.getConfigurationTargetFromSettingsResource(resource);
194
		return this.openOrSwitchSettings(target, resource);
S
Sandeep Somavarapu 已提交
195 196
	}

J
Johannes Rieken 已提交
197
	private openSettings2(): Promise<IEditor> {
198 199 200
		const input = this.settingsEditor2Input;
		return this.editorGroupService.activeGroup.openEditor(input)
			.then(() => this.editorGroupService.activeGroup.activeControl);
201 202
	}

J
Johannes Rieken 已提交
203
	openGlobalSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor> {
204 205 206 207
		jsonEditor = typeof jsonEditor === 'undefined' ?
			this.configurationService.getValue('workbench.settings.editor') === 'json' :
			jsonEditor;

208 209
		return jsonEditor ?
			this.openOrSwitchSettings(ConfigurationTarget.USER, this.userSettingsResource, options, group) :
210
			this.openOrSwitchSettings2(ConfigurationTarget.USER, undefined, options, group);
R
Rob Lourens 已提交
211 212
	}

J
Johannes Rieken 已提交
213
	openWorkspaceSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor> {
214 215 216 217
		jsonEditor = typeof jsonEditor === 'undefined' ?
			this.configurationService.getValue('workbench.settings.editor') === 'json' :
			jsonEditor;

218
		if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
219
			this.notificationService.info(nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
R
Rob Lourens 已提交
220
			return Promise.resolve(null);
221
		}
222 223 224

		return jsonEditor ?
			this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, options, group) :
225
			this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE, undefined, options, group);
226 227
	}

J
Johannes Rieken 已提交
228
	openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor> {
229 230 231 232
		jsonEditor = typeof jsonEditor === 'undefined' ?
			this.configurationService.getValue('workbench.settings.editor') === 'json' :
			jsonEditor;

233 234
		return jsonEditor ?
			this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder), options, group) :
235
			this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE_FOLDER, folder, options, group);
236 237
	}

J
Johannes Rieken 已提交
238
	switchSettings(target: ConfigurationTarget, resource: URI, jsonEditor?: boolean): Promise<void> {
239
		if (!jsonEditor) {
240
			return this.doOpenSettings2(target, resource).then(() => null);
241 242
		}

B
Benjamin Pasero 已提交
243 244
		const activeControl = this.editorService.activeControl;
		if (activeControl && activeControl.input instanceof PreferencesEditorInput) {
245
			return this.doSwitchSettings(target, resource, activeControl.input, activeControl.group).then(() => null);
246
		} else {
247
			return this.doOpenSettings(target, resource).then(() => null);
248
		}
249 250
	}

J
Johannes Rieken 已提交
251
	openGlobalKeybindingSettings(textual: boolean): Promise<void> {
K
kieferrm 已提交
252
		/* __GDPR__
K
kieferrm 已提交
253
			"openKeybindings" : {
K
kieferrm 已提交
254
				"textual" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
K
kieferrm 已提交
255 256
			}
		*/
257
		this.telemetryService.publicLog('openKeybindings', { textual });
S
Sandeep Somavarapu 已提交
258
		if (textual) {
259
			const emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to override the defaults") + '\n[\n]';
S
Sandeep Somavarapu 已提交
260
			const editableKeybindings = URI.file(this.environmentService.appKeybindingsPath);
N
Nilesh 已提交
261
			const openDefaultKeybindings = !!this.configurationService.getValue('workbench.settings.openDefaultKeybindings');
S
Sandeep Somavarapu 已提交
262 263

			// Create as needed and open in editor
S
Sandeep Somavarapu 已提交
264 265
			return this.createIfNotExists(editableKeybindings, emptyContents).then(() => {
				if (openDefaultKeybindings) {
N
Nilesh 已提交
266 267
					const activeEditorGroup = this.editorGroupService.activeGroup;
					const sideEditorGroup = this.editorGroupService.addGroup(activeEditorGroup.id, GroupDirection.RIGHT);
R
Rob Lourens 已提交
268
					return Promise.all([
S
Sandeep Somavarapu 已提交
269 270
						this.editorService.openEditor({ resource: this.defaultKeybindingsResource, options: { pinned: true, preserveFocus: true, revealIfOpened: true }, label: nls.localize('defaultKeybindings', "Default Keybindings"), description: '' }),
						this.editorService.openEditor({ resource: editableKeybindings, options: { pinned: true, revealIfOpened: true } }, sideEditorGroup.id)
N
Nilesh 已提交
271
					]).then(editors => void 0);
S
Sandeep Somavarapu 已提交
272
				} else {
S
Sandeep Somavarapu 已提交
273
					return this.editorService.openEditor({ resource: editableKeybindings, options: { pinned: true, revealIfOpened: true } }).then(() => void 0);
S
Sandeep Somavarapu 已提交
274
				}
S
Sandeep Somavarapu 已提交
275 276
			});
		}
277

S
Sandeep Somavarapu 已提交
278
		return this.editorService.openEditor(this.instantiationService.createInstance(KeybindingsEditorInput), { pinned: true, revealIfOpened: true }).then(() => null);
279 280
	}

J
Johannes Rieken 已提交
281
	openDefaultKeybindingsFile(): Promise<IEditor> {
282
		return this.editorService.openEditor({ resource: this.defaultKeybindingsResource, label: nls.localize('defaultKeybindings', "Default Keybindings") });
N
Nilesh 已提交
283 284
	}

285
	configureSettingsForLanguage(language: string): void {
286
		this.openGlobalSettings(true)
S
Sandeep Somavarapu 已提交
287 288 289 290
			.then(editor => this.createPreferencesEditorModel(this.userSettingsResource)
				.then((settingsModel: IPreferencesEditorModel<ISetting>) => {
					const codeEditor = getCodeEditor(editor.getControl());
					if (codeEditor) {
S
Sandeep Somavarapu 已提交
291
						this.addLanguageOverrideEntry(language, settingsModel, codeEditor)
S
Sandeep Somavarapu 已提交
292 293 294
							.then(position => {
								if (codeEditor) {
									codeEditor.setPosition(position);
295
									codeEditor.revealLine(position.lineNumber);
S
Sandeep Somavarapu 已提交
296 297 298 299 300
									codeEditor.focus();
								}
							});
					}
				}));
301 302
	}

J
Johannes Rieken 已提交
303
	private openOrSwitchSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: ISettingsEditorOptions, group: IEditorGroup = this.editorGroupService.activeGroup): Promise<IEditor> {
B
Benjamin Pasero 已提交
304
		const editorInput = this.getActiveSettingsEditorInput(group);
305
		if (editorInput && editorInput.master.getResource().fsPath !== resource.fsPath) {
306
			return this.doSwitchSettings(configurationTarget, resource, editorInput, group, options);
307
		}
B
Benjamin Pasero 已提交
308
		return this.doOpenSettings(configurationTarget, resource, options, group);
309 310
	}

J
Johannes Rieken 已提交
311
	private openOrSwitchSettings2(configurationTarget: ConfigurationTarget, folderUri?: URI, options?: ISettingsEditorOptions, group: IEditorGroup = this.editorGroupService.activeGroup): Promise<IEditor> {
312
		return this.doOpenSettings2(configurationTarget, folderUri, options, group);
313 314
	}

J
Johannes Rieken 已提交
315
	private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor> {
S
Sandeep Somavarapu 已提交
316
		const openDefaultSettings = !!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING);
317

318
		return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource)
319
			.then(editableSettingsEditorInput => {
320 321 322
				if (!options) {
					options = { pinned: true };
				} else {
323
					options = assign(options, { pinned: true });
324 325
				}

326
				if (openDefaultSettings) {
327 328 329 330 331 332 333 334
					const activeEditorGroup = this.editorGroupService.activeGroup;
					const sideEditorGroup = this.editorGroupService.addGroup(activeEditorGroup.id, GroupDirection.RIGHT);
					return Promise.all([
						this.editorService.openEditor({ resource: this.defaultSettingsRawResource, options: { pinned: true, preserveFocus: true, revealIfOpened: true }, label: nls.localize('defaultSettings', "Default Settings"), description: '' }),
						this.editorService.openEditor(editableSettingsEditorInput, { pinned: true, revealIfOpened: true }, sideEditorGroup.id)
					]).then(() => null);
				} else {
					return this.editorService.openEditor(editableSettingsEditorInput, SettingsEditorOptions.create(options), group);
335
				}
336
			});
337 338
	}

339 340 341 342
	public createSettings2EditorModel(): Settings2EditorModel {
		return this.instantiationService.createInstance(Settings2EditorModel, this.getDefaultSettings(ConfigurationTarget.USER));
	}

J
Johannes Rieken 已提交
343
	private doOpenSettings2(target: ConfigurationTarget, folderUri: URI | undefined, options?: IEditorOptions, group?: IEditorGroup): Promise<IEditor> {
344 345 346 347 348 349 350 351
		const input = this.settingsEditor2Input;
		const settingsOptions: ISettingsEditorOptions = {
			...options,
			target,
			folderUri
		};

		return this.editorService.openEditor(input, SettingsEditorOptions.create(settingsOptions), group);
352 353
	}

J
Johannes Rieken 已提交
354
	private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise<IEditor> {
355 356
		return this.getOrCreateEditableSettingsEditorInput(target, this.getEditableSettingsURI(target, resource))
			.then(toInput => {
B
Benjamin Pasero 已提交
357 358 359 360 361
				return group.openEditor(input).then(() => {
					const replaceWith = new PreferencesEditorInput(this.getPreferencesEditorInputName(target, resource), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(target)), toInput);

					return group.replaceEditors([{
						editor: input,
362 363
						replacement: replaceWith,
						options: SettingsEditorOptions.create(options)
B
Benjamin Pasero 已提交
364 365 366 367
					}]).then(() => {
						this.lastOpenedSettingsInput = replaceWith;
						return group.activeControl;
					});
368 369 370 371
				});
			});
	}

372
	private getActiveSettingsEditorInput(group: IEditorGroup = this.editorGroupService.activeGroup): PreferencesEditorInput {
B
Benjamin Pasero 已提交
373
		return <PreferencesEditorInput>group.editors.filter(e => e instanceof PreferencesEditorInput)[0];
374 375
	}

S
Sandeep Somavarapu 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	private getConfigurationTargetFromSettingsResource(resource: URI): ConfigurationTarget {
		if (this.userSettingsResource.toString() === resource.toString()) {
			return ConfigurationTarget.USER;
		}

		const workspaceSettingsResource = this.workspaceSettingsResource;
		if (workspaceSettingsResource && workspaceSettingsResource.toString() === resource.toString()) {
			return ConfigurationTarget.WORKSPACE;
		}

		const folder = this.contextService.getWorkspaceFolder(resource);
		if (folder) {
			return ConfigurationTarget.WORKSPACE_FOLDER;
		}

		return ConfigurationTarget.USER;
	}

S
Sandeep Somavarapu 已提交
394 395 396 397
	private getConfigurationTargetFromDefaultSettingsResource(uri: URI) {
		return this.isDefaultWorkspaceSettingsResource(uri) ? ConfigurationTarget.WORKSPACE : this.isDefaultFolderSettingsResource(uri) ? ConfigurationTarget.WORKSPACE_FOLDER : ConfigurationTarget.USER;
	}

R
Rob Lourens 已提交
398
	private isDefaultSettingsResource(uri: URI): boolean {
S
Sandeep Somavarapu 已提交
399 400 401 402
		return this.isDefaultUserSettingsResource(uri) || this.isDefaultWorkspaceSettingsResource(uri) || this.isDefaultFolderSettingsResource(uri);
	}

	private isDefaultUserSettingsResource(uri: URI): boolean {
403
		return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?settings\.json$/);
R
Rob Lourens 已提交
404 405
	}

S
Sandeep Somavarapu 已提交
406 407 408 409 410
	private isDefaultWorkspaceSettingsResource(uri: URI): boolean {
		return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?workspaceSettings\.json$/);
	}

	private isDefaultFolderSettingsResource(uri: URI): boolean {
411
		return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?resourceSettings\.json$/);
R
Rob Lourens 已提交
412 413
	}

S
Sandeep Somavarapu 已提交
414
	private getDefaultSettingsResource(configurationTarget: ConfigurationTarget): URI {
S
Sandeep Somavarapu 已提交
415 416 417 418 419
		switch (configurationTarget) {
			case ConfigurationTarget.WORKSPACE:
				return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultWorkspaceSettingsUriCounter++}/workspaceSettings.json` });
			case ConfigurationTarget.WORKSPACE_FOLDER:
				return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultFolderSettingsUriCounter++}/resourceSettings.json` });
S
Sandeep Somavarapu 已提交
420
		}
S
Sandeep Somavarapu 已提交
421
		return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultUserSettingsUriCounter++}/settings.json` });
S
Sandeep Somavarapu 已提交
422 423
	}

424 425
	private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string {
		const name = getSettingsTargetName(target, resource, this.contextService);
426
		return target === ConfigurationTarget.WORKSPACE_FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name;
427 428
	}

J
Johannes Rieken 已提交
429
	private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget, resource: URI): Promise<EditorInput> {
430 431
		return this.createSettingsIfNotExists(target, resource)
			.then(() => <EditorInput>this.editorService.createInput({ resource }));
432 433
	}

J
Johannes Rieken 已提交
434
	private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): Promise<SettingsEditorModel> {
435
		const settingsUri = this.getEditableSettingsURI(configurationTarget, resource);
436
		if (settingsUri) {
S
Sandeep Somavarapu 已提交
437 438 439 440
			const workspace = this.contextService.getWorkspace();
			if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) {
				return this.textModelResolverService.createModelReference(settingsUri)
					.then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget));
441
			}
442
			return this.textModelResolverService.createModelReference(settingsUri)
S
Sandeep Somavarapu 已提交
443
				.then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget));
444
		}
R
Rob Lourens 已提交
445
		return Promise.resolve<SettingsEditorModel>(null);
446 447
	}

J
Johannes Rieken 已提交
448
	private createDefaultSettingsEditorModel(defaultSettingsUri: URI): Promise<DefaultSettingsEditorModel> {
449 450
		return this.textModelResolverService.createModelReference(defaultSettingsUri)
			.then(reference => {
S
Sandeep Somavarapu 已提交
451 452
				const target = this.getConfigurationTargetFromDefaultSettingsResource(defaultSettingsUri);
				return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, this.getDefaultSettings(target));
453 454 455
			});
	}

S
Sandeep Somavarapu 已提交
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
	private getDefaultSettings(target: ConfigurationTarget): DefaultSettings {
		if (target === ConfigurationTarget.WORKSPACE) {
			if (!this._defaultWorkspaceSettingsContentModel) {
				this._defaultWorkspaceSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), target);
			}
			return this._defaultWorkspaceSettingsContentModel;
		}
		if (target === ConfigurationTarget.WORKSPACE_FOLDER) {
			if (!this._defaultFolderSettingsContentModel) {
				this._defaultFolderSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), target);
			}
			return this._defaultFolderSettingsContentModel;
		}
		if (!this._defaultUserSettingsContentModel) {
			this._defaultUserSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), target);
471
		}
S
Sandeep Somavarapu 已提交
472
		return this._defaultUserSettingsContentModel;
473 474
	}

475
	private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI {
476 477 478 479
		switch (configurationTarget) {
			case ConfigurationTarget.USER:
				return URI.file(this.environmentService.appSettingsPath);
			case ConfigurationTarget.WORKSPACE:
480
				if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
481 482
					return null;
				}
483
				const workspace = this.contextService.getWorkspace();
484
				return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH);
485
			case ConfigurationTarget.WORKSPACE_FOLDER:
S
Sandeep Somavarapu 已提交
486
				const folder = this.contextService.getWorkspaceFolder(resource);
487
				return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null;
488
		}
489
		return null;
490 491
	}

J
Johannes Rieken 已提交
492
	private createSettingsIfNotExists(target: ConfigurationTarget, resource: URI): Promise<void> {
493
		if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && target === ConfigurationTarget.WORKSPACE) {
R
Rob Lourens 已提交
494 495 496 497 498 499
			const workspaceConfig = this.contextService.getWorkspace().configuration;
			if (!workspaceConfig) {
				return Promise.resolve(null);
			}

			return this.fileService.resolveContent(workspaceConfig)
S
Sandeep Somavarapu 已提交
500 501
				.then(content => {
					if (Object.keys(parse(content.value)).indexOf('settings') === -1) {
502
						return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(void 0, () => { });
S
Sandeep Somavarapu 已提交
503 504 505
					}
					return null;
				});
506
		}
S
Sandeep Somavarapu 已提交
507
		return this.createIfNotExists(resource, emptyEditableSettingsContent).then(() => { });
508 509
	}

J
Johannes Rieken 已提交
510
	private createIfNotExists(resource: URI, contents: string): Promise<any> {
511
		return this.fileService.resolveContent(resource, { acceptTextOnly: true }).then(void 0, error => {
512
			if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) {
513
				return this.fileService.updateContent(resource, contents).then(void 0, error => {
R
Rob Lourens 已提交
514
					return Promise.reject(new Error(nls.localize('fail.createSettings', "Unable to create '{0}' ({1}).", this.labelService.getUriLabel(resource, { relative: true }), error)));
515 516 517
				});
			}

R
Rob Lourens 已提交
518
			return Promise.reject(error);
519 520 521
		});
	}

522 523
	private getMostCommonlyUsedSettings(): string[] {
		return [
S
Sandeep Somavarapu 已提交
524
			'files.autoSave',
525
			'editor.fontSize',
S
Sandeep Somavarapu 已提交
526 527 528
			'editor.fontFamily',
			'editor.tabSize',
			'editor.renderWhitespace',
S
Sandeep Somavarapu 已提交
529
			'editor.cursorStyle',
530
			'editor.multiCursorModifier',
S
Sandeep Somavarapu 已提交
531
			'editor.insertSpaces',
532
			'editor.wordWrap',
533
			'files.exclude',
S
Sandeep Somavarapu 已提交
534
			'files.associations'
535
		];
S
Sandeep Somavarapu 已提交
536
	}
537

J
Johannes Rieken 已提交
538
	private addLanguageOverrideEntry(language: string, settingsModel: IPreferencesEditorModel<ISetting>, codeEditor: ICodeEditor): Promise<IPosition> {
S
Sandeep Somavarapu 已提交
539 540 541
		const languageKey = `[${language}]`;
		let setting = settingsModel.getPreference(languageKey);
		const model = codeEditor.getModel();
S
Sandeep Somavarapu 已提交
542 543
		const configuration = this.configurationService.getValue<{ editor: { tabSize: number; insertSpaces: boolean } }>();
		const eol = model.getEOL();
S
Sandeep Somavarapu 已提交
544 545 546
		if (setting) {
			if (setting.overrides.length) {
				const lastSetting = setting.overrides[setting.overrides.length - 1];
S
Sandeep Somavarapu 已提交
547
				return Promise.resolve({ lineNumber: lastSetting.valueRange.endLineNumber, column: model.getLineMaxColumn(lastSetting.valueRange.endLineNumber) });
S
Sandeep Somavarapu 已提交
548
			}
R
Rob Lourens 已提交
549
			return Promise.resolve({ lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 });
S
Sandeep Somavarapu 已提交
550 551 552 553 554 555 556 557 558 559
		}
		return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER)
			.then(() => {
				setting = settingsModel.getPreference(languageKey);
				let content = eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor);
				let editOperation = EditOperation.insert(new Position(setting.valueRange.endLineNumber, setting.valueRange.endColumn - 1), content);
				model.pushEditOperations([], [editOperation], () => []);
				let lineNumber = setting.valueRange.endLineNumber + 1;
				settingsModel.dispose();
				return { lineNumber, column: model.getLineMaxColumn(lineNumber) };
560 561 562
			});
	}

A
Alex Dima 已提交
563
	private spaces(count: number, { tabSize, insertSpaces }: { tabSize: number; insertSpaces: boolean }): string {
564 565 566
		return insertSpaces ? strings.repeat(' ', tabSize * count) : strings.repeat('\t', count);
	}

567
	public dispose(): void {
568
		this._onDispose.fire();
569 570
		super.dispose();
	}
571
}