<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Event, Emitter } from 'vs/base/common/event';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IExplorerService, IEditableData, IFilesConfiguration, SortOrder, SortOrderConfiguration } from 'vs/workbench/parts/files/common/files';
import { ExplorerItem, ExplorerModel } from 'vs/workbench/parts/files/common/explorerModel';
import { URI } from 'vs/base/common/uri';
import { FileOperationEvent, FileOperation, IFileStat, IFileService, FileChangesEvent, FILES_EXCLUDE_CONFIG, FileChangeType, IResolveFileOptions } from 'vs/platform/files/common/files';
import { dirname } from 'vs/base/common/resources';
import { memoize } from 'vs/base/common/decorators';
import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IExpression } from 'vs/base/common/glob';

function getFileEventsExcludes(configurationService: IConfigurationService, root?: URI): IExpression {
	const scope = root ? { resource: root } : undefined;
	const configuration = scope ? configurationService.getValue<IFilesConfiguration>(scope) : configurationService.getValue<IFilesConfiguration>();

	return (configuration && configuration.files && configuration.files.exclude) || Object.create(null);
}

export class ExplorerService implements IExplorerService {
	_serviceBrand: any;

	private static readonly EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first

	private _onDidChangeRoots = new Emitter<void>();
	private _onDidChangeItem = new Emitter<ExplorerItem | undefined>();
	private _onDidChangeEditable = new Emitter<ExplorerItem>();
	private _onDidSelectItem = new Emitter<{ item?: ExplorerItem, reveal?: boolean }>();
	private disposables: IDisposable[] = [];
	private editableStats = new Map<ExplorerItem, IEditableData>();
	private _sortOrder: SortOrder;

	constructor(
		@IFileService private fileService: IFileService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IConfigurationService private configurationService: IConfigurationService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
	) { }

	get roots(): ExplorerItem[] {
		return this.model.roots;
	}

	get onDidChangeRoots(): Event<void> {
		return this._onDidChangeRoots.event;
	}

	get onDidChangeItem(): Event<ExplorerItem | undefined> {
		return this._onDidChangeItem.event;
	}

	get onDidChangeEditable(): Event<ExplorerItem> {
		return this._onDidChangeEditable.event;
	}

	get onDidSelectItem(): Event<{ item?: ExplorerItem, reveal?: boolean }> {
		return this._onDidSelectItem.event;
	}

	get sortOrder(): SortOrder {
		return this._sortOrder;
	}

	// Memoized locals
	@memoize private get fileEventsFilter(): ResourceGlobMatcher {
		const fileEventsFilter = this.instantiationService.createInstance(
			ResourceGlobMatcher,
			(root?: URI) => getFileEventsExcludes(this.configurationService, root),
			(event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG)
		);
		this.disposables.push(fileEventsFilter);

		return fileEventsFilter;
	}

	@memoize get model(): ExplorerModel {
		const model = new ExplorerModel(this.contextService);
		this.disposables.push(model);
		this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
		this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
		this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue<IFilesConfiguration>())));
		this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(() => this._onDidChangeItem.fire(undefined)));
		this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire()));

		return model;
	}

	// IExplorerService methods

	findClosest(resource: URI): ExplorerItem | null {
		return this.model.findClosest(resource);
	}

	setEditable(stat: ExplorerItem, data: IEditableData): void {
		this.editableStats.set(stat, data);
		this._onDidChangeEditable.fire(stat);
	}

	getEditableData(stat: ExplorerItem): IEditableData | undefined {
		return this.editableStats.get(stat);
	}

	select(resource: URI, reveal?: boolean): Promise<void> {
		const fileStat = this.findClosest(resource);
		if (fileStat) {
			this._onDidSelectItem.fire({ item: fileStat, reveal });
			return Promise.resolve(undefined);
		}

		// Stat needs to be resolved first and then revealed
		const options: IResolveFileOptions = { resolveTo: [resource] };
		const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
		const rootUri = workspaceFolder ? workspaceFolder.uri : this.roots[0].resource;
		const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!;
		return this.fileService.resolveFile(rootUri, options).then(stat => {

			// Convert to model
			const modelStat = ExplorerItem.create(stat, undefined, options.resolveTo);
			// Update Input with disk Stat
			ExplorerItem.mergeLocalWithDisk(modelStat, root);

			// Select and Reveal
			this._onDidSelectItem.fire({ item: root.find(resource) || undefined, reveal });
		}, () => {
			root.isError = true;
			this._onDidChangeItem.fire(root);
		});
	}

	refresh(): void {
		this.model.roots.forEach(r => r.isDirectoryResolved = false);
		this._onDidChangeItem.fire(undefined);<commit_msg>explorer: root need sto be refreshed when an element is selected<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Event, Emitter } from 'vs/base/common/event';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IExplorerService, IEditableData, IFilesConfiguration, SortOrder, SortOrderConfiguration } from 'vs/workbench/parts/files/common/files';
import { ExplorerItem, ExplorerModel } from 'vs/workbench/parts/files/common/explorerModel';
import { URI } from 'vs/base/common/uri';
import { FileOperationEvent, FileOperation, IFileStat, IFileService, FileChangesEvent, FILES_EXCLUDE_CONFIG, FileChangeType, IResolveFileOptions } from 'vs/platform/files/common/files';
import { dirname } from 'vs/base/common/resources';
import { memoize } from 'vs/base/common/decorators';
import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IExpression } from 'vs/base/common/glob';

function getFileEventsExcludes(configurationService: IConfigurationService, root?: URI): IExpression {
	const scope = root ? { resource: root } : undefined;
	const configuration = scope ? configurationService.getValue<IFilesConfiguration>(scope) : configurationService.getValue<IFilesConfiguration>();

	return (configuration && configuration.files && configuration.files.exclude) || Object.create(null);
}

export class ExplorerService implements IExplorerService {
	_serviceBrand: any;

	private static readonly EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first

	private _onDidChangeRoots = new Emitter<void>();
	private _onDidChangeItem = new Emitter<ExplorerItem | undefined>();
	private _onDidChangeEditable = new Emitter<ExplorerItem>();
	private _onDidSelectItem = new Emitter<{ item?: ExplorerItem, reveal?: boolean }>();
	private disposables: IDisposable[] = [];
	private editableStats = new Map<ExplorerItem, IEditableData>();
	private _sortOrder: SortOrder;

	constructor(
		@IFileService private fileService: IFileService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IConfigurationService private configurationService: IConfigurationService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
	) { }

	get roots(): ExplorerItem[] {
		return this.model.roots;
	}

	get onDidChangeRoots(): Event<void> {
		return this._onDidChangeRoots.event;
	}

	get onDidChangeItem(): Event<ExplorerItem | undefined> {
		return this._onDidChangeItem.event;
	}

	get onDidChangeEditable(): Event<ExplorerItem> {
		return this._onDidChangeEditable.event;
	}

	get onDidSelectItem(): Event<{ item?: ExplorerItem, reveal?: boolean }> {
		return this._onDidSelectItem.event;
	}

	get sortOrder(): SortOrder {
		return this._sortOrder;
	}

	// Memoized locals
	@memoize private get fileEventsFilter(): ResourceGlobMatcher {
		const fileEventsFilter = this.instantiationService.createInstance(
			ResourceGlobMatcher,
			(root?: URI) => getFileEventsExcludes(this.configurationService, root),
			(event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG)
		);
		this.disposables.push(fileEventsFilter);

		return fileEventsFilter;
	}

	@memoize get model(): ExplorerModel {
		const model = new ExplorerModel(this.contextService);
		this.disposables.push(model);
		this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
		this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
		this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue<IFilesConfiguration>())));
		this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(() => this._onDidChangeItem.fire(undefined)));
		this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire()));

		return model;
	}

	// IExplorerService methods

	findClosest(resource: URI): ExplorerItem | null {
		return this.model.findClosest(resource);
	}

	setEditable(stat: ExplorerItem, data: IEditableData): void {
		this.editableStats.set(stat, data);
		this._onDidChangeEditable.fire(stat);
	}

	getEditableData(stat: ExplorerItem): IEditableData | undefined {
		return this.editableStats.get(stat);
	}

	select(resource: URI, reveal?: boolean): Promise<void> {
		const fileStat = this.findClosest(resource);
		if (fileStat) {
			this._onDidSelectItem.fire({ item: fileStat, reveal });
			return Promise.resolve(undefined);
		}

		// Stat needs to be resolved first and then revealed
		const options: IResolveFileOptions = { resolveTo: [resource] };
		const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
		const rootUri = workspaceFolder ? workspaceFolder.uri : this.roots[0].resource;
		const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!;
		return this.fileService.resolveFile(rootUri, options).then(stat => {

			// Convert to model
			const modelStat = ExplorerItem.create(stat, undefined, options.resolveTo);
			// Update Input with disk Stat
			ExplorerItem.mergeLocalWithDisk(modelStat, root);
			this._onDidChangeItem.fire(root);

			// Select and Reveal
			this._onDidSelectItem.fire({ item: root.find(resource) || undefined, reveal });
		}, () => {
			root.isError = true;
			this._onDidChangeItem.fire(root);
		});
	}

	refresh(): void {
		this.model.roots.forEach(r => r.isDirectoryResolved = false);
		this._onDidChangeItem.fire(undefined);
{'fraction_non_alphanumeric': 0.14048908583620548, 'fraction_numerical': 0.0006564910553093714, 'mean_word_length': 4.850696111377821, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 51, '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': '6100391', 'n_tokens_mistral': 3649, 'n_tokens_neox': 3388, 'n_words': 744}