preferencesService.ts 24.7 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
import * as network from 'vs/base/common/network';
7 8 9 10
import { TPromise } from 'vs/base/common/winjs.base';
import * as nls from 'vs/nls';
import URI from 'vs/base/common/uri';
import * as labels from 'vs/base/common/labels';
11
import * as strings from 'vs/base/common/strings';
S
Sandeep Somavarapu 已提交
12
import { Disposable } from 'vs/base/common/lifecycle';
13
import { Emitter } from 'vs/base/common/event';
14
import { EditorInput } from 'vs/workbench/common/editor';
15
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
16
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
17
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
18
import { Position as EditorPosition, IEditor, IEditorOptions } from 'vs/platform/editor/common/editor';
A
Alex Dima 已提交
19
import { ITextModel } from 'vs/editor/common/model';
20
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
21
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
22 23
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
S
Sandeep Somavarapu 已提交
24 25
import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/services/preferences/common/preferences';
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettings, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
C
Christof Marti 已提交
26
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
27
import { DefaultPreferencesEditorInput, PreferencesEditorInput, KeybindingsEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
28
import { ITextModelService } from 'vs/editor/common/services/resolverService';
29
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
30
import { EditOperation } from 'vs/editor/common/core/editOperation';
A
Alex Dima 已提交
31
import { Position, IPosition } from 'vs/editor/common/core/position';
32 33
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IModelService } from 'vs/editor/common/services/modelService';
B
Benjamin Pasero 已提交
34
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
35
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
36
import { IModeService } from 'vs/editor/common/services/modeService';
S
Sandeep Somavarapu 已提交
37
import { parse } from 'vs/base/common/json';
38
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
39
import { INotificationService } from 'vs/platform/notification/common/notification';
40
import { assign } from 'vs/base/common/objects';
41
import { INextEditorService } from 'vs/workbench/services/editor/common/nextEditorService';
B
Benjamin Pasero 已提交
42
import { INextEditorGroup, INextEditorGroupsService } from 'vs/workbench/services/group/common/nextEditorGroupsService';
43

S
Sandeep Somavarapu 已提交
44 45
const emptyEditableSettingsContent = '{\n}';

46
export class PreferencesService extends Disposable implements IPreferencesService {
47 48

	_serviceBrand: any;
49

50
	private lastOpenedSettingsInput: PreferencesEditorInput = null;
51

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

S
Sandeep Somavarapu 已提交
54 55 56 57 58 59
	private _defaultUserSettingsUriCounter = 0;
	private _defaultUserSettingsContentModel: DefaultSettings;
	private _defaultWorkspaceSettingsUriCounter = 0;
	private _defaultWorkspaceSettingsContentModel: DefaultSettings;
	private _defaultFolderSettingsUriCounter = 0;
	private _defaultFolderSettingsContentModel: DefaultSettings;
R
Rob Lourens 已提交
60

61 62
	constructor(
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
63
		@INextEditorService private nextEditorService: INextEditorService,
64
		@IEditorGroupService private editorGroupService: IEditorGroupService,
B
Benjamin Pasero 已提交
65
		@INextEditorGroupsService private nextEditorGroupService: INextEditorGroupsService,
66 67
		@IFileService private fileService: IFileService,
		@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
68
		@INotificationService private notificationService: INotificationService,
69 70 71
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IEnvironmentService private environmentService: IEnvironmentService,
72
		@ITelemetryService private telemetryService: ITelemetryService,
73
		@ITextModelService private textModelResolverService: ITextModelService,
74
		@IKeybindingService keybindingService: IKeybindingService,
75
		@IModelService private modelService: IModelService,
76 77
		@IJSONEditingService private jsonEditingService: IJSONEditingService,
		@IModeService private modeService: IModeService
78 79
	) {
		super();
80 81 82 83 84 85 86 87
		// 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;
			}
88
			modelService.updateModel(model, defaultKeybindingsContents(keybindingService));
89
		});
90 91
	}

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

95 96 97 98 99 100 101 102
	get userSettingsResource(): URI {
		return this.getEditableSettingsURI(ConfigurationTarget.USER);
	}

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

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

A
Alex Dima 已提交
107
	resolveModel(uri: URI): TPromise<ITextModel> {
S
Sandeep Somavarapu 已提交
108
		if (this.isDefaultSettingsResource(uri)) {
S
Sandeep Somavarapu 已提交
109

S
Sandeep Somavarapu 已提交
110
			const target = this.getConfigurationTargetFromDefaultSettingsResource(uri);
111
			const mode = this.modeService.getOrCreateMode('jsonc');
S
Sandeep Somavarapu 已提交
112 113 114 115 116 117 118 119 120 121
			const model = this._register(this.modelService.createModel('', mode, uri));

			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 已提交
122
					defaultSettings = this.getDefaultSettings(target);
S
Sandeep Somavarapu 已提交
123
					this.modelService.updateModel(model, defaultSettings.parse());
124
					defaultSettings._onDidChange.fire();
S
Sandeep Somavarapu 已提交
125 126 127 128 129
				}
			});

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

			return TPromise.as(model);
135 136
		}

S
Sandeep Somavarapu 已提交
137
		if (this.defaultSettingsRawResource.toString() === uri.toString()) {
S
Sandeep Somavarapu 已提交
138
			let defaultSettings: DefaultSettings = this.getDefaultSettings(ConfigurationTarget.USER);
139
			const mode = this.modeService.getOrCreateMode('jsonc');
S
Sandeep Somavarapu 已提交
140 141 142 143
			const model = this._register(this.modelService.createModel(defaultSettings.raw, mode, uri));
			return TPromise.as(model);
		}

144
		if (this.defaultKeybindingsResource.toString() === uri.toString()) {
S
Sandeep Somavarapu 已提交
145
			const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri);
146
			const mode = this.modeService.getOrCreateMode('jsonc');
S
Sandeep Somavarapu 已提交
147 148
			const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, mode, uri));
			return TPromise.as(model);
149 150 151 152 153 154
		}

		return TPromise.as(null);
	}

	createPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel<any>> {
S
Sandeep Somavarapu 已提交
155
		if (this.isDefaultSettingsResource(uri)) {
156
			return this.createDefaultSettingsEditorModel(uri);
157 158
		}

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

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

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

172
		return TPromise.wrap<IPreferencesEditorModel<any>>(null);
173 174
	}

S
Sandeep Somavarapu 已提交
175 176 177 178
	openRawDefaultSettings(): TPromise<void> {
		return this.editorService.openEditor({ resource: this.defaultSettingsRawResource }, EditorPosition.ONE) as TPromise<any>;
	}

S
Sandeep Somavarapu 已提交
179
	openSettings(): TPromise<IEditor> {
180 181
		const editorInput = this.getActiveSettingsEditorInput() || this.lastOpenedSettingsInput;
		const resource = editorInput ? editorInput.master.getResource() : this.userSettingsResource;
S
Sandeep Somavarapu 已提交
182
		const target = this.getConfigurationTargetFromSettingsResource(resource);
183
		return this.openOrSwitchSettings(target, resource);
S
Sandeep Somavarapu 已提交
184 185
	}

B
Benjamin Pasero 已提交
186 187
	openGlobalSettings(options?: IEditorOptions, group?: INextEditorGroup): TPromise<IEditor> {
		return this.openOrSwitchSettings(ConfigurationTarget.USER, this.userSettingsResource, options, group);
188 189
	}

R
Rob Lourens 已提交
190
	openSettings2(): TPromise<IEditor> {
191
		return this.editorService.openEditor(this.instantiationService.createInstance(SettingsEditor2Input), { pinned: true }).then(() => null);
R
Rob Lourens 已提交
192 193
	}

B
Benjamin Pasero 已提交
194
	openWorkspaceSettings(options?: IEditorOptions, group?: INextEditorGroup): TPromise<IEditor> {
195
		if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
196
			this.notificationService.info(nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
S
Sandeep Somavarapu 已提交
197
			return TPromise.as(null);
198
		}
B
Benjamin Pasero 已提交
199
		return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, options, group);
200 201
	}

B
Benjamin Pasero 已提交
202 203
	openFolderSettings(folder: URI, options?: IEditorOptions, group?: INextEditorGroup): TPromise<IEditor> {
		return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder), options, group);
204 205 206
	}

	switchSettings(target: ConfigurationTarget, resource: URI): TPromise<void> {
207
		const activeEditor = this.editorService.getActiveEditor();
S
Sandeep Somavarapu 已提交
208
		if (activeEditor && activeEditor.input instanceof PreferencesEditorInput) {
B
Benjamin Pasero 已提交
209
			return this.doSwitchSettings(target, resource, activeEditor.input, null).then(() => null);
210
		} else {
211
			return this.doOpenSettings(target, resource).then(() => null);
212
		}
213 214
	}

S
Sandeep Somavarapu 已提交
215
	openGlobalKeybindingSettings(textual: boolean): TPromise<void> {
K
kieferrm 已提交
216
		/* __GDPR__
K
kieferrm 已提交
217
			"openKeybindings" : {
K
kieferrm 已提交
218
				"textual" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
K
kieferrm 已提交
219 220
			}
		*/
221
		this.telemetryService.publicLog('openKeybindings', { textual });
S
Sandeep Somavarapu 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234
		if (textual) {
			const emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to overwrite the defaults") + '\n[\n]';
			const editableKeybindings = URI.file(this.environmentService.appKeybindingsPath);

			// Create as needed and open in editor
			return this.createIfNotExists(editableKeybindings, emptyContents).then(() => {
				return this.editorService.openEditors([
					{ input: { resource: this.defaultKeybindingsResource, options: { pinned: true }, label: nls.localize('defaultKeybindings', "Default Keybindings"), description: '' }, position: EditorPosition.ONE },
					{ input: { resource: editableKeybindings, options: { pinned: true } }, position: EditorPosition.TWO },
				]).then(() => {
					this.editorGroupService.focusGroup(EditorPosition.TWO);
				});
			});
235

S
Sandeep Somavarapu 已提交
236
		}
237
		return (this.nextEditorService.openEditor(this.instantiationService.createInstance(KeybindingsEditorInput), { pinned: true }) as TPromise).then(() => null);
238 239
	}

240 241 242 243 244 245 246 247 248 249 250 251
	configureSettingsForLanguage(language: string): void {
		this.openGlobalSettings()
			.then(editor => {
				const codeEditor = getCodeEditor(editor);
				this.getPosition(language, codeEditor)
					.then(position => {
						codeEditor.setPosition(position);
						codeEditor.focus();
					});
			});
	}

B
Benjamin Pasero 已提交
252 253
	private openOrSwitchSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: IEditorOptions, group: INextEditorGroup = this.nextEditorGroupService.activeGroup): TPromise<IEditor> {
		const editorInput = this.getActiveSettingsEditorInput(group);
254
		if (editorInput && editorInput.master.getResource().fsPath !== resource.fsPath) {
B
Benjamin Pasero 已提交
255
			return this.doSwitchSettings(configurationTarget, resource, editorInput, group);
256
		}
B
Benjamin Pasero 已提交
257
		return this.doOpenSettings(configurationTarget, resource, options, group);
258 259
	}

B
Benjamin Pasero 已提交
260
	private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: IEditorOptions, group?: INextEditorGroup): TPromise<IEditor> {
S
Sandeep Somavarapu 已提交
261
		const openDefaultSettings = !!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING);
262
		return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource)
263
			.then(editableSettingsEditorInput => {
264 265 266
				if (!options) {
					options = { pinned: true };
				} else {
267
					options = assign(options, { pinned: true });
268 269
				}

270
				if (openDefaultSettings) {
S
Sandeep Somavarapu 已提交
271
					const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget));
272
					const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, <EditorInput>editableSettingsEditorInput);
273
					this.lastOpenedSettingsInput = preferencesEditorInput;
B
Benjamin Pasero 已提交
274
					return this.nextEditorService.openEditor(preferencesEditorInput, options, group);
275
				}
B
Benjamin Pasero 已提交
276
				return this.nextEditorService.openEditor(editableSettingsEditorInput, options, group);
277
			});
278 279
	}

B
Benjamin Pasero 已提交
280
	private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: INextEditorGroup): TPromise<IEditor> {
281 282 283
		return this.getOrCreateEditableSettingsEditorInput(target, this.getEditableSettingsURI(target, resource))
			.then(toInput => {
				const replaceWith = new PreferencesEditorInput(this.getPreferencesEditorInputName(target, resource), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(target)), toInput);
B
Benjamin Pasero 已提交
284 285 286 287 288

				return group.replaceEditors([{
					editor: input,
					replacement: replaceWith
				}]).then(() => {
289
					this.lastOpenedSettingsInput = replaceWith;
B
Benjamin Pasero 已提交
290
					return group.activeControl;
291 292 293 294
				});
			});
	}

B
Benjamin Pasero 已提交
295 296
	private getActiveSettingsEditorInput(group: INextEditorGroup = this.nextEditorGroupService.activeGroup): PreferencesEditorInput {
		return <PreferencesEditorInput>group.editors.filter(e => e instanceof PreferencesEditorInput)[0];
297 298
	}

S
Sandeep Somavarapu 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	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 已提交
317 318 319 320
	private getConfigurationTargetFromDefaultSettingsResource(uri: URI) {
		return this.isDefaultWorkspaceSettingsResource(uri) ? ConfigurationTarget.WORKSPACE : this.isDefaultFolderSettingsResource(uri) ? ConfigurationTarget.WORKSPACE_FOLDER : ConfigurationTarget.USER;
	}

R
Rob Lourens 已提交
321
	private isDefaultSettingsResource(uri: URI): boolean {
S
Sandeep Somavarapu 已提交
322 323 324 325
		return this.isDefaultUserSettingsResource(uri) || this.isDefaultWorkspaceSettingsResource(uri) || this.isDefaultFolderSettingsResource(uri);
	}

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

S
Sandeep Somavarapu 已提交
329 330 331 332 333
	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 {
334
		return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?resourceSettings\.json$/);
R
Rob Lourens 已提交
335 336
	}

S
Sandeep Somavarapu 已提交
337
	private getDefaultSettingsResource(configurationTarget: ConfigurationTarget): URI {
S
Sandeep Somavarapu 已提交
338 339 340 341 342
		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 已提交
343
		}
S
Sandeep Somavarapu 已提交
344
		return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultUserSettingsUriCounter++}/settings.json` });
S
Sandeep Somavarapu 已提交
345 346
	}

347 348
	private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string {
		const name = getSettingsTargetName(target, resource, this.contextService);
349
		return target === ConfigurationTarget.WORKSPACE_FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name;
350 351
	}

352 353 354
	private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget, resource: URI): TPromise<EditorInput> {
		return this.createSettingsIfNotExists(target, resource)
			.then(() => <EditorInput>this.editorService.createInput({ resource }));
355 356
	}

357 358
	private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): TPromise<SettingsEditorModel> {
		const settingsUri = this.getEditableSettingsURI(configurationTarget, resource);
359
		if (settingsUri) {
S
Sandeep Somavarapu 已提交
360 361 362 363
			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));
364
			}
365
			return this.textModelResolverService.createModelReference(settingsUri)
S
Sandeep Somavarapu 已提交
366
				.then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget));
367
		}
368
		return TPromise.wrap<SettingsEditorModel>(null);
369 370
	}

371 372 373
	private createDefaultSettingsEditorModel(defaultSettingsUri: URI): TPromise<DefaultSettingsEditorModel> {
		return this.textModelResolverService.createModelReference(defaultSettingsUri)
			.then(reference => {
S
Sandeep Somavarapu 已提交
374 375
				const target = this.getConfigurationTargetFromDefaultSettingsResource(defaultSettingsUri);
				return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, this.getDefaultSettings(target));
376 377 378
			});
	}

S
Sandeep Somavarapu 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	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);
394
		}
S
Sandeep Somavarapu 已提交
395
		return this._defaultUserSettingsContentModel;
396 397
	}

398
	private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI {
399 400 401 402
		switch (configurationTarget) {
			case ConfigurationTarget.USER:
				return URI.file(this.environmentService.appSettingsPath);
			case ConfigurationTarget.WORKSPACE:
403
				if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
404 405
					return null;
				}
406
				const workspace = this.contextService.getWorkspace();
407
				return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH);
408
			case ConfigurationTarget.WORKSPACE_FOLDER:
S
Sandeep Somavarapu 已提交
409
				const folder = this.contextService.getWorkspaceFolder(resource);
410
				return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null;
411
		}
412
		return null;
413 414
	}

415
	private createSettingsIfNotExists(target: ConfigurationTarget, resource: URI): TPromise<void> {
416
		if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && target === ConfigurationTarget.WORKSPACE) {
S
Sandeep Somavarapu 已提交
417 418 419 420 421 422 423
			return this.fileService.resolveContent(this.contextService.getWorkspace().configuration)
				.then(content => {
					if (Object.keys(parse(content.value)).indexOf('settings') === -1) {
						return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(null, () => { });
					}
					return null;
				});
424
		}
S
Sandeep Somavarapu 已提交
425
		return this.createIfNotExists(resource, emptyEditableSettingsContent).then(() => { });
426 427
	}

R
Ron Buckton 已提交
428
	private createIfNotExists(resource: URI, contents: string): TPromise<any> {
429
		return this.fileService.resolveContent(resource, { acceptTextOnly: true }).then(null, error => {
430
			if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) {
431
				return this.fileService.updateContent(resource, contents).then(null, error => {
R
Ron Buckton 已提交
432
					return TPromise.wrapError(new Error(nls.localize('fail.createSettings', "Unable to create '{0}' ({1}).", labels.getPathLabel(resource, this.contextService, this.environmentService), error)));
433 434 435
				});
			}

R
Ron Buckton 已提交
436
			return TPromise.wrapError(error);
437 438 439
		});
	}

440 441
	private getMostCommonlyUsedSettings(): string[] {
		return [
S
Sandeep Somavarapu 已提交
442
			'files.autoSave',
443
			'editor.fontSize',
S
Sandeep Somavarapu 已提交
444 445 446
			'editor.fontFamily',
			'editor.tabSize',
			'editor.renderWhitespace',
S
Sandeep Somavarapu 已提交
447
			'editor.cursorStyle',
448
			'editor.multiCursorModifier',
S
Sandeep Somavarapu 已提交
449
			'editor.insertSpaces',
450
			'editor.wordWrap',
451
			'files.exclude',
S
Sandeep Somavarapu 已提交
452
			'files.associations'
453
		];
S
Sandeep Somavarapu 已提交
454
	}
455

456
	private getPosition(language: string, codeEditor: ICodeEditor): TPromise<IPosition> {
S
Sandeep Somavarapu 已提交
457
		return this.createPreferencesEditorModel(this.userSettingsResource)
458 459 460 461
			.then((settingsModel: IPreferencesEditorModel<ISetting>) => {
				const languageKey = `[${language}]`;
				let setting = settingsModel.getPreference(languageKey);
				const model = codeEditor.getModel();
462 463
				const configuration = this.configurationService.getValue<{ editor: { tabSize: number; insertSpaces: boolean }, files: { eol: string } }>();
				const eol = configuration.files && configuration.files.eol;
464 465 466 467 468
				if (setting) {
					if (setting.overrides.length) {
						const lastSetting = setting.overrides[setting.overrides.length - 1];
						let content;
						if (lastSetting.valueRange.endLineNumber === setting.range.endLineNumber) {
469
							content = ',' + eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor);
470
						} else {
471
							content = ',' + eol + this.spaces(2, configuration.editor);
472 473 474 475 476 477 478
						}
						const editOperation = EditOperation.insert(new Position(lastSetting.valueRange.endLineNumber, lastSetting.valueRange.endColumn), content);
						model.pushEditOperations([], [editOperation], () => []);
						return { lineNumber: lastSetting.valueRange.endLineNumber + 1, column: model.getLineMaxColumn(lastSetting.valueRange.endLineNumber + 1) };
					}
					return { lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 };
				}
479
				return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER)
480 481
					.then(() => {
						setting = settingsModel.getPreference(languageKey);
482
						let content = eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor);
483 484 485
						let editOperation = EditOperation.insert(new Position(setting.valueRange.endLineNumber, setting.valueRange.endColumn - 1), content);
						model.pushEditOperations([], [editOperation], () => []);
						let lineNumber = setting.valueRange.endLineNumber + 1;
S
Sandeep Somavarapu 已提交
486
						settingsModel.dispose();
487 488 489 490 491
						return { lineNumber, column: model.getLineMaxColumn(lineNumber) };
					});
			});
	}

A
Alex Dima 已提交
492
	private spaces(count: number, { tabSize, insertSpaces }: { tabSize: number; insertSpaces: boolean }): string {
493 494 495
		return insertSpaces ? strings.repeat(' ', tabSize * count) : strings.repeat('\t', count);
	}

496
	public dispose(): void {
497
		this._onDispose.fire();
498 499
		super.dispose();
	}
500
}