fileService.ts 7.8 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';

import nls = require('vs/nls');
8
import {TPromise} from 'vs/base/common/winjs.base';
9
import {IDisposable} from 'vs/base/common/lifecycle';
E
Erich Gamma 已提交
10
import paths = require('vs/base/common/paths');
B
wip  
Benjamin Pasero 已提交
11
import encoding = require('vs/base/node/encoding');
E
Erich Gamma 已提交
12 13 14 15
import errors = require('vs/base/common/errors');
import strings = require('vs/base/common/strings');
import uri from 'vs/base/common/uri';
import timer = require('vs/base/common/timer');
16
import {IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IContent, IImportResult, IResolveContentOptions, IUpdateContentOptions} from 'vs/platform/files/common/files';
E
Erich Gamma 已提交
17
import {FileService as NodeFileService, IFileServiceOptions, IEncodingOverride} from 'vs/workbench/services/files/node/fileService';
18
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
E
Erich Gamma 已提交
19 20
import {IEventService} from 'vs/platform/event/common/event';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
21 22
import {Action} from 'vs/base/common/actions';
import {IMessageService, IMessageWithAction, Severity} from 'vs/platform/message/common/message';
E
Erich Gamma 已提交
23

B
Benjamin Pasero 已提交
24
import {shell} from 'electron';
E
Erich Gamma 已提交
25

26 27 28
// If we run with .NET framework < 4.5, we need to detect this error to inform the user
const NET_VERSION_ERROR = 'System.MissingMethodException';

29
export class FileService implements IFileService {
E
Erich Gamma 已提交
30

31 32 33
	public serviceId = IFileService;

	private raw: IFileService;
E
Erich Gamma 已提交
34

35
	private configurationChangeListenerUnbind: IDisposable;
E
Erich Gamma 已提交
36 37 38 39

	constructor(
		private configurationService: IConfigurationService,
		private eventService: IEventService,
40 41
		private contextService: IWorkspaceContextService,
		private messageService: IMessageService
E
Erich Gamma 已提交
42
	) {
43
		const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
E
Erich Gamma 已提交
44

45 46 47 48 49 50
		// adjust encodings (TODO@Ben knowledge on settings location ('.vscode') is hardcoded)
		let encodingOverride: IEncodingOverride[] = [];
		encodingOverride.push({ resource: uri.file(this.contextService.getConfiguration().env.appSettingsHome), encoding: encoding.UTF8 });
		if (this.contextService.getWorkspace()) {
			encodingOverride.push({ resource: uri.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode')), encoding: encoding.UTF8 });
		}
E
Erich Gamma 已提交
51

52 53 54 55 56 57 58
		let watcherIgnoredPatterns: string[] = [];
		if (configuration.files && configuration.files.watcherExclude) {
			watcherIgnoredPatterns = Object.keys(configuration.files.watcherExclude).filter(k => !!configuration.files.watcherExclude[k]);
		}

		// build config
		let fileServiceConfig: IFileServiceOptions = {
59
			errorLogger: (msg: string) => this.onFileServiceError(msg),
60 61 62 63 64 65 66 67
			encoding: configuration.files && configuration.files.encoding,
			encodingOverride: encodingOverride,
			watcherIgnoredPatterns: watcherIgnoredPatterns,
			verboseLogging: this.contextService.getConfiguration().env.verboseLogging
		};

		// create service
		let workspace = this.contextService.getWorkspace();
68
		this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService);
E
Erich Gamma 已提交
69 70

		// Listeners
71
		this.registerListeners();
E
Erich Gamma 已提交
72 73
	}

74 75 76 77 78 79 80 81 82
	private onFileServiceError(msg: string): void {
		errors.onUnexpectedError(msg);

		// Detect if we run < .NET Framework 4.5
		if (msg && msg.indexOf(NET_VERSION_ERROR) >= 0) {
			this.messageService.show(Severity.Warning, <IMessageWithAction>{
				message: nls.localize('netVersionError', "The Microsoft .NET Framework 4.5 is required. Please follow the link to install it."),
				actions: [
					new Action('install.net', nls.localize('installNet', "Download .NET Framework 4.5"), null, true, () => {
B
Benjamin Pasero 已提交
83
						shell.openExternal('https://go.microsoft.com/fwlink/?LinkId=786533');
84 85 86 87 88 89 90 91

						return TPromise.as(true);
					})
				]
			});
		}
	}

E
Erich Gamma 已提交
92 93 94
	private registerListeners(): void {

		// Config Changes
95
		this.configurationChangeListenerUnbind = this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(e.config));
E
Erich Gamma 已提交
96 97
	}

98
	private onConfigurationChange(configuration: IFilesConfiguration): void {
E
Erich Gamma 已提交
99 100 101 102
		this.updateOptions(configuration.files);
	}

	public updateOptions(options: any): void {
103
		this.raw.updateOptions(options);
E
Erich Gamma 已提交
104 105
	}

106 107
	public resolveFile(resource: uri, options?: IResolveFileOptions): TPromise<IFileStat> {
		return this.raw.resolveFile(resource, options);
E
Erich Gamma 已提交
108 109
	}

110 111 112 113
	public existsFile(resource: uri): TPromise<boolean> {
		return this.raw.existsFile(resource);
	}

114
	public resolveContent(resource: uri, options?: IResolveContentOptions): TPromise<IContent> {
E
Erich Gamma 已提交
115 116 117
		let contentId = resource.toString();
		let timerEvent = timer.start(timer.Topic.WORKBENCH, strings.format('Load {0}', contentId));

118 119
		return this.raw.resolveContent(resource, options).then((result) => {
			timerEvent.stop();
E
Erich Gamma 已提交
120

121
			return result;
E
Erich Gamma 已提交
122 123 124
		});
	}

125 126
	public resolveContents(resources: uri[]): TPromise<IContent[]> {
		return this.raw.resolveContents(resources);
E
Erich Gamma 已提交
127 128
	}

129
	public updateContent(resource: uri, value: string, options?: IUpdateContentOptions): TPromise<IFileStat> {
E
Erich Gamma 已提交
130 131
		let timerEvent = timer.start(timer.Topic.WORKBENCH, strings.format('Save {0}', resource.toString()));

132 133
		return this.raw.updateContent(resource, value, options).then((result) => {
			timerEvent.stop();
E
Erich Gamma 已提交
134

135 136 137
			return result;
		}, (error) => {
			timerEvent.stop();
E
Erich Gamma 已提交
138

139
			return TPromise.wrapError(error);
E
Erich Gamma 已提交
140 141 142
		});
	}

143 144
	public moveFile(source: uri, target: uri, overwrite?: boolean): TPromise<IFileStat> {
		return this.raw.moveFile(source, target, overwrite);
E
Erich Gamma 已提交
145 146
	}

147 148
	public copyFile(source: uri, target: uri, overwrite?: boolean): TPromise<IFileStat> {
		return this.raw.copyFile(source, target, overwrite);
E
Erich Gamma 已提交
149 150
	}

151 152
	public createFile(resource: uri, content?: string): TPromise<IFileStat> {
		return this.raw.createFile(resource, content);
E
Erich Gamma 已提交
153 154
	}

155 156
	public createFolder(resource: uri): TPromise<IFileStat> {
		return this.raw.createFolder(resource);
E
Erich Gamma 已提交
157 158
	}

159 160
	public rename(resource: uri, newName: string): TPromise<IFileStat> {
		return this.raw.rename(resource, newName);
E
Erich Gamma 已提交
161 162 163 164 165 166 167
	}

	public del(resource: uri, useTrash?: boolean): TPromise<void> {
		if (useTrash) {
			return this.doMoveItemToTrash(resource);
		}

168
		return this.raw.del(resource);
E
Erich Gamma 已提交
169 170
	}

171
	private doMoveItemToTrash(resource: uri): TPromise<void> {
E
Erich Gamma 已提交
172 173
		let workspace = this.contextService.getWorkspace();
		if (!workspace) {
174
			return TPromise.wrapError<void>('Need a workspace to use this');
E
Erich Gamma 已提交
175 176 177 178
		}

		let absolutePath = resource.fsPath;

B
Benjamin Pasero 已提交
179
		let result = shell.moveItemToTrash(absolutePath);
E
Erich Gamma 已提交
180
		if (!result) {
181
			return TPromise.wrapError<void>(new Error(nls.localize('trashFailed', "Failed to move '{0}' to the trash", paths.basename(absolutePath))));
E
Erich Gamma 已提交
182 183
		}

A
Alex Dima 已提交
184
		return TPromise.as(null);
E
Erich Gamma 已提交
185 186
	}

187 188 189 190 191 192
	public importFile(source: uri, targetFolder: uri): TPromise<IImportResult> {
		return this.raw.importFile(source, targetFolder).then((result) => {
			return <IImportResult>{
				isNew: result && result.isNew,
				stat: result && result.stat
			};
E
Erich Gamma 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
		});
	}

	public watchFileChanges(resource: uri): void {
		if (!resource) {
			return;
		}

		if (resource.scheme !== 'file') {
			return; // only support files
		}

		// return early if the resource is inside the workspace for which we have another watcher in place
		if (this.contextService.isInsideWorkspace(resource)) {
			return;
		}

210
		this.raw.watchFileChanges(resource);
E
Erich Gamma 已提交
211 212 213 214 215
	}

	public unwatchFileChanges(resource: uri): void;
	public unwatchFileChanges(path: string): void;
	public unwatchFileChanges(arg1: any): void {
216
		this.raw.unwatchFileChanges(arg1);
E
Erich Gamma 已提交
217 218 219 220 221 222
	}

	public dispose(): void {

		// Listeners
		if (this.configurationChangeListenerUnbind) {
223
			this.configurationChangeListenerUnbind.dispose();
E
Erich Gamma 已提交
224 225 226 227
			this.configurationChangeListenerUnbind = null;
		}

		// Dispose service
228
		this.raw.dispose();
E
Erich Gamma 已提交
229 230
	}
}