Path: blob/main/src/vs/workbench/contrib/preferences/common/settingsFilesystemProvider.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { NotSupportedError } from '../../../../base/common/errors.js';6import { IDisposable, Disposable } from '../../../../base/common/lifecycle.js';7import { Schemas } from '../../../../base/common/network.js';8import { URI } from '../../../../base/common/uri.js';9import { FileChangeType, FilePermission, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileChange, IFileDeleteOptions, IFileOverwriteOptions, IFileSystemProviderWithFileReadWriteCapability, IStat, IWatchOptions } from '../../../../platform/files/common/files.js';10import { IPreferencesService } from '../../../services/preferences/common/preferences.js';11import { Event, Emitter } from '../../../../base/common/event.js';12import { Registry } from '../../../../platform/registry/common/platform.js';13import * as JSONContributionRegistry from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';14import { VSBuffer } from '../../../../base/common/buffer.js';15import { ILogService, LogLevel } from '../../../../platform/log/common/log.js';16import { isEqual } from '../../../../base/common/resources.js';1718const schemaRegistry = Registry.as<JSONContributionRegistry.IJSONContributionRegistry>(JSONContributionRegistry.Extensions.JSONContribution);192021export class SettingsFileSystemProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability {2223static readonly SCHEMA = Schemas.vscode;2425protected readonly _onDidChangeFile = this._register(new Emitter<readonly IFileChange[]>());26readonly onDidChangeFile = this._onDidChangeFile.event;2728private static SCHEMA_ASSOCIATIONS = URI.parse(`${Schemas.vscode}://schemas-associations/schemas-associations.json`);2930constructor(31@IPreferencesService private readonly preferencesService: IPreferencesService,32@ILogService private readonly logService: ILogService33) {34super();35this._register(schemaRegistry.onDidChangeSchema(schemaUri => {36this._onDidChangeFile.fire([{ resource: URI.parse(schemaUri), type: FileChangeType.UPDATED }]);37}));38this._register(schemaRegistry.onDidChangeSchemaAssociations(() => {39this._onDidChangeFile.fire([{ resource: SettingsFileSystemProvider.SCHEMA_ASSOCIATIONS, type: FileChangeType.UPDATED }]);40}));41this._register(preferencesService.onDidDefaultSettingsContentChanged(uri => {42this._onDidChangeFile.fire([{ resource: uri, type: FileChangeType.UPDATED }]);43}));44}4546readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly + FileSystemProviderCapabilities.FileReadWrite;4748async readFile(uri: URI): Promise<Uint8Array> {49if (uri.scheme !== SettingsFileSystemProvider.SCHEMA) {50throw new NotSupportedError();51}52let content: string | undefined;53if (uri.authority === 'schemas') {54content = this.getSchemaContent(uri);55} else if (uri.authority === SettingsFileSystemProvider.SCHEMA_ASSOCIATIONS.authority) {56content = JSON.stringify(schemaRegistry.getSchemaAssociations());57} else if (uri.authority === 'defaultsettings') {58content = this.preferencesService.getDefaultSettingsContent(uri);59}60if (content) {61return VSBuffer.fromString(content).buffer;62}63throw FileSystemProviderErrorCode.FileNotFound;64}6566async stat(uri: URI): Promise<IStat> {67if (schemaRegistry.hasSchemaContent(uri.toString()) || this.preferencesService.hasDefaultSettingsContent(uri)) {68const currentTime = Date.now();69return {70type: FileType.File,71permissions: FilePermission.Readonly,72mtime: currentTime,73ctime: currentTime,74size: 075};76}77if (isEqual(uri, SettingsFileSystemProvider.SCHEMA_ASSOCIATIONS)) {78const currentTime = Date.now();79return {80type: FileType.File,81permissions: FilePermission.Readonly,82mtime: currentTime,83ctime: currentTime,84size: 085};86}87throw FileSystemProviderErrorCode.FileNotFound;88}8990readonly onDidChangeCapabilities = Event.None;9192watch(resource: URI, opts: IWatchOptions): IDisposable { return Disposable.None; }9394async mkdir(resource: URI): Promise<void> { }95async readdir(resource: URI): Promise<[string, FileType][]> { return []; }9697async rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void> { }98async delete(resource: URI, opts: IFileDeleteOptions): Promise<void> { }99100async writeFile() {101throw new NotSupportedError();102}103104private getSchemaContent(uri: URI): string {105const startTime = Date.now();106const content = schemaRegistry.getSchemaContent(uri.toString()) ?? '{}' /* Use empty schema if not yet registered */;107const logLevel = this.logService.getLevel();108if (logLevel === LogLevel.Debug || logLevel === LogLevel.Trace) {109const endTime = Date.now();110const uncompressed = JSON.stringify(schemaRegistry.getSchemaContributions().schemas[uri.toString()]);111this.logService.debug(`${uri.toString()}: ${uncompressed.length} -> ${content.length} (${Math.round((uncompressed.length - content.length) / uncompressed.length * 100)}%) Took ${endTime - startTime}ms`);112}113return content;114}115}116117118