<commit_before>/*---------------------------------------------------------------------------------------------
 *  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 URI from 'vs/base/common/uri';
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { TPromise } from 'vs/base/common/winjs.base';
import { basename, join } from 'path';
import { IDisposable } from 'vs/base/common/lifecycle';
import { groupBy, isFalsyOrEmpty, distinct } from 'vs/base/common/arrays';
import { compare } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { Progress } from 'vs/platform/progress/common/progress';
import { decodeStream, encode } from 'vs/base/node/encoding';
import { StringTrieMap } from 'vs/base/common/map';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';

function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise<IFileStat> {
	const [resource, stat] = tuple;
	const fileStat: IFileStat = {
		isDirectory: false,
		hasChildren: false,
		resource: resource,
		name: basename(resource.path),
		mtime: stat.mtime,
		size: stat.size,
		etag: stat.mtime.toString(29) + stat.size.toString(31),
	};

	if (stat.type === FileType.File) {
		// done
		return TPromise.as(fileStat);

	} else {
		// dir -> resolve
		return provider.readdir(resource).then(entries => {
			fileStat.isDirectory = true;
			fileStat.hasChildren = entries.length > 0;

			if (recurse && recurse([resource, stat])) {
				// resolve children if requested
				return TPromise.join(entries.map(stat => toIFileStat(provider, stat, recurse))).then(children => {
					fileStat.children = children;
					return fileStat;
				});
			} else {
				return fileStat;
			}
		});
	}
}

export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): TPromise<IFileStat> {

	const trie = new StringTrieMap<true>();
	trie.insert(tuple[0].toString(), true);

	if (!isFalsyOrEmpty(to)) {
		to.forEach(uri => trie.insert(uri.toString(), true));
	}

	return toIFileStat(provider, tuple, candidate => {
		const sub = trie.findSuperstr(candidate[0].toString());
		return !!sub;
	});
}

export class RemoteFileService extends FileService {

	private readonly _provider = new Map<string, IFileSystemProvider>();
	private _supportedSchemes: string[];

	constructor(
		@IExtensionService private readonly _extensionService: IExtensionService,
		@IStorageService private readonly _storageService: IStorageService,
		@IConfigurationService configurationService: IConfigurationService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEnvironmentService environmentService: IEnvironmentService,
		@ILifecycleService lifecycleService: ILifecycleService,
		@IMessageService messageService: IMessageService,
		@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService,
	) {
		super(
			configurationService,
			contextService,
			environmentService,
			lifecycleService,
			messageService,
			_storageService,
			textResourceConfigurationService,
		);

		this._supportedSchemes = JSON.parse(this._storageService.get('remote_schemes', undefined, '[]'));
	}

	registerProvider(authority: string, provider: IFileSystemProvider): IDisposable {
		if (this._provider.has(authority)) {
			throw new Error();
		}

		this._supportedSchemes.push(authority);
		this._storageService.store('remote_schemes', JSON.stringify(distinct(this._supportedSchemes)));

		this._provider.set(authority, provider);
		const reg = provider.onDidChange(changes => {
			// forward change events
			this._onFileChanges.fire(new FileChangesEvent(changes));
		});
		return {
			dispose: () => {
				this._provider.delete(authority);
				reg.dispose();
			}
		};
	}

	supportResource(resource: URI): boolean {
		return resource.scheme === Schemas.file
			|| this._provider.has(resource.scheme)
			// TODO@remote
			|| this._supportedSchemes.indexOf(resource.scheme) >= 0;
	}

	// --- stat

	private _withProvider(resource: URI): TPromise<IFileSystemProvider> {
		return this._extensionService.activateByEvent('onFileSystemAccess:' + resource.scheme).then(() => {
			const provider = this._provider.get(resource.scheme);
			if (!provider) {
				const err = new Error();
				err.name = 'ENOPRO';
				err.message = `no provider for ${resource.toString}`;
				throw err;
			}<commit_msg>actually invoke a function... #34704<commit_after>/*---------------------------------------------------------------------------------------------
 *  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 URI from 'vs/base/common/uri';
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { TPromise } from 'vs/base/common/winjs.base';
import { basename, join } from 'path';
import { IDisposable } from 'vs/base/common/lifecycle';
import { groupBy, isFalsyOrEmpty, distinct } from 'vs/base/common/arrays';
import { compare } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { Progress } from 'vs/platform/progress/common/progress';
import { decodeStream, encode } from 'vs/base/node/encoding';
import { StringTrieMap } from 'vs/base/common/map';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';

function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise<IFileStat> {
	const [resource, stat] = tuple;
	const fileStat: IFileStat = {
		isDirectory: false,
		hasChildren: false,
		resource: resource,
		name: basename(resource.path),
		mtime: stat.mtime,
		size: stat.size,
		etag: stat.mtime.toString(29) + stat.size.toString(31),
	};

	if (stat.type === FileType.File) {
		// done
		return TPromise.as(fileStat);

	} else {
		// dir -> resolve
		return provider.readdir(resource).then(entries => {
			fileStat.isDirectory = true;
			fileStat.hasChildren = entries.length > 0;

			if (recurse && recurse([resource, stat])) {
				// resolve children if requested
				return TPromise.join(entries.map(stat => toIFileStat(provider, stat, recurse))).then(children => {
					fileStat.children = children;
					return fileStat;
				});
			} else {
				return fileStat;
			}
		});
	}
}

export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): TPromise<IFileStat> {

	const trie = new StringTrieMap<true>();
	trie.insert(tuple[0].toString(), true);

	if (!isFalsyOrEmpty(to)) {
		to.forEach(uri => trie.insert(uri.toString(), true));
	}

	return toIFileStat(provider, tuple, candidate => {
		const sub = trie.findSuperstr(candidate[0].toString());
		return !!sub;
	});
}

export class RemoteFileService extends FileService {

	private readonly _provider = new Map<string, IFileSystemProvider>();
	private _supportedSchemes: string[];

	constructor(
		@IExtensionService private readonly _extensionService: IExtensionService,
		@IStorageService private readonly _storageService: IStorageService,
		@IConfigurationService configurationService: IConfigurationService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEnvironmentService environmentService: IEnvironmentService,
		@ILifecycleService lifecycleService: ILifecycleService,
		@IMessageService messageService: IMessageService,
		@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService,
	) {
		super(
			configurationService,
			contextService,
			environmentService,
			lifecycleService,
			messageService,
			_storageService,
			textResourceConfigurationService,
		);

		this._supportedSchemes = JSON.parse(this._storageService.get('remote_schemes', undefined, '[]'));
	}

	registerProvider(authority: string, provider: IFileSystemProvider): IDisposable {
		if (this._provider.has(authority)) {
			throw new Error();
		}

		this._supportedSchemes.push(authority);
		this._storageService.store('remote_schemes', JSON.stringify(distinct(this._supportedSchemes)));

		this._provider.set(authority, provider);
		const reg = provider.onDidChange(changes => {
			// forward change events
			this._onFileChanges.fire(new FileChangesEvent(changes));
		});
		return {
			dispose: () => {
				this._provider.delete(authority);
				reg.dispose();
			}
		};
	}

	supportResource(resource: URI): boolean {
		return resource.scheme === Schemas.file
			|| this._provider.has(resource.scheme)
			// TODO@remote
			|| this._supportedSchemes.indexOf(resource.scheme) >= 0;
	}

	// --- stat

	private _withProvider(resource: URI): TPromise<IFileSystemProvider> {
		return this._extensionService.activateByEvent('onFileSystemAccess:' + resource.scheme).then(() => {
			const provider = this._provider.get(resource.scheme);
			if (!provider) {
				const err = new Error();
				err.name = 'ENOPRO';
				err.message = `no provider for ${resource.toString()}`;
				throw err;
			}
{'fraction_non_alphanumeric': 0.15200926668448722, 'fraction_numerical': 0.0018711574445335472, 'mean_word_length': 4.329534662867996, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1919492', 'n_tokens_mistral': 3421, 'n_tokens_neox': 3147, 'n_words': 686}