configurationService.ts 4.6 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 {TPromise} from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
9 10 11 12
import uri from 'vs/base/common/uri';
import strings = require('vs/base/common/strings');
import platform = require('vs/base/common/platform');
import paths = require('vs/base/common/paths');
13
import extfs = require('vs/base/node/extfs');
E
Erich Gamma 已提交
14 15 16 17 18 19
import {IConfigFile} from 'vs/platform/configuration/common/model';
import objects = require('vs/base/common/objects');
import {IStat, IContent, ConfigurationService as CommonConfigurationService} from 'vs/platform/configuration/common/configurationService';
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {OptionsChangeEvent, EventType} from 'vs/workbench/common/events';
import {IEventService} from 'vs/platform/event/common/event';
A
Alex Dima 已提交
20
import {IDisposable} from 'vs/base/common/lifecycle';
21 22 23 24
import {readFile, writeFile} from 'vs/base/node/pfs';
import {JSONPath} from 'vs/base/common/json';
import {applyEdits} from 'vs/base/common/jsonFormatter';
import {setProperty} from 'vs/base/common/jsonEdit';
E
Erich Gamma 已提交
25 26 27

export class ConfigurationService extends CommonConfigurationService {

28
	public _serviceBrand: any;
29

A
Alex Dima 已提交
30
	private toDispose: IDisposable;
E
Erich Gamma 已提交
31

B
Benjamin Pasero 已提交
32 33 34 35
	constructor(
		contextService: IWorkspaceContextService,
		eventService: IEventService
	) {
E
Erich Gamma 已提交
36
		super(contextService, eventService);
37

E
Erich Gamma 已提交
38 39 40
		this.registerListeners();
	}

41 42 43
	protected registerListeners(): void {
		super.registerListeners();

A
Alex Dima 已提交
44
		this.toDispose = this.eventService.addListener2(EventType.WORKBENCH_OPTIONS_CHANGED, (e) => this.onOptionsChanged(e));
45 46 47 48 49 50 51 52
	}

	private onOptionsChanged(e: OptionsChangeEvent): void {
		if (e.key === 'globalSettings') {
			this.handleConfigurationChange();
		}
	}

E
Erich Gamma 已提交
53
	protected resolveContents(resources: uri[]): TPromise<IContent[]> {
B
Benjamin Pasero 已提交
54
		const contents: IContent[] = [];
E
Erich Gamma 已提交
55

56
		return TPromise.join(resources.map((resource) => {
E
Erich Gamma 已提交
57 58 59 60 61 62 63
			return this.resolveContent(resource).then((content) => {
				contents.push(content);
			});
		})).then(() => contents);
	}

	protected resolveContent(resource: uri): TPromise<IContent> {
64
		return readFile(resource.fsPath).then(contents => ({resource, value: contents.toString()}));
E
Erich Gamma 已提交
65 66 67 68
	}

	protected resolveStat(resource: uri): TPromise<IStat> {
		return new TPromise<IStat>((c, e) => {
69
			extfs.readdir(resource.fsPath, (error, children) => {
E
Erich Gamma 已提交
70
				if (error) {
71
					if ((<any>error).code === 'ENOTDIR') {
E
Erich Gamma 已提交
72 73 74 75 76 77 78 79 80 81 82
						c({
							resource: resource,
							isDirectory: false
						});
					} else {
						e(error);
					}
				} else {
					c({
						resource: resource,
						isDirectory: true,
83
						children: children.map((child) => {
E
Erich Gamma 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
							if (platform.isMacintosh) {
								child = strings.normalizeNFC(child); // Mac: uses NFD unicode form on disk, but we want NFC
							}

							return {
								resource: uri.file(paths.join(resource.fsPath, child))
							};
						})
					});
				}
			});
		});
	}

	protected loadWorkspaceConfiguration(section?: string): TPromise<{ [relativeWorkspacePath: string]: IConfigFile }> {

100
		// Return early if we don't have a workspace
E
Erich Gamma 已提交
101
		if (!this.contextService.getWorkspace()) {
A
Alex Dima 已提交
102
			return TPromise.as({});
E
Erich Gamma 已提交
103 104
		}

B
Benjamin Pasero 已提交
105
		return super.loadWorkspaceConfiguration(section);
E
Erich Gamma 已提交
106 107
	}

108 109 110 111 112 113 114 115 116 117 118 119
	protected loadGlobalConfiguration(): { contents: any; parseErrors?: string[]; } {
		const defaults = super.loadGlobalConfiguration();
		const globalSettings = this.contextService.getOptions().globalSettings;

		return {
			contents: objects.mixin(
				objects.clone(defaults.contents),	// target: default values (but don't modify!)
				globalSettings.settings,			// source: global configured values
				true								// overwrite
			),
			parseErrors: globalSettings.settingsParseErrors
		};
E
Erich Gamma 已提交
120 121
	}

122
	public setUserConfiguration(key: any, value: any) : Thenable<void> {
B
Benjamin Pasero 已提交
123 124
		const appSettingsPath = this.contextService.getConfiguration().env.appSettingsPath;
		
125
		return readFile(appSettingsPath, 'utf8').then(content => {
B
Benjamin Pasero 已提交
126 127 128 129
			const {tabSize, insertSpaces} = this.getConfiguration<{ tabSize: number; insertSpaces: boolean }>('editor');
			const path: JSONPath = typeof key === 'string' ? (<string> key).split('.') : <JSONPath> key;
			const edits = setProperty(content, path, value, {insertSpaces, tabSize, eol: '\n'});

130
			content = applyEdits(content, edits);
B
Benjamin Pasero 已提交
131

132 133 134 135
			return writeFile(appSettingsPath, content, 'utf8');
		});
	}

E
Erich Gamma 已提交
136
	public dispose(): void {
137 138
		super.dispose();

A
Alex Dima 已提交
139
		this.toDispose.dispose();
E
Erich Gamma 已提交
140 141
	}
}