// ***************************************************************************** // Copyright (C) 2019 Ericsson and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** /* eslint-disable @typescript-eslint/no-explicit-any */ import { inject, injectable, postConstruct, named } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; import { UserPreferenceProvider, UserPreferenceProviderFactory } from '../common/user-preference-provider'; import { PreferenceProviderImpl, PreferenceConfigurations, PreferenceResolveResult, PreferenceUtils, ILogger } from '@theia/core'; export const UserStorageLocationProvider = Symbol('UserStorageLocationProvider'); /** * Binds together preference section prefs providers for user-level preferences. */ @injectable() export class UserConfigsPreferenceProvider extends PreferenceProviderImpl { @inject(UserPreferenceProviderFactory) protected readonly providerFactory: UserPreferenceProviderFactory; @inject(UserStorageLocationProvider) private userStorageLocationProvider: () => Promise; @inject(PreferenceConfigurations) protected readonly configurations: PreferenceConfigurations; @inject(ILogger) @named('preferences:UserConfigsPreferenceProvider') protected readonly logger: ILogger; protected readonly providers = new Map(); @postConstruct() protected init(): void { this.doInit(); } protected async doInit(): Promise { const userStorageUri = await this.userStorageLocationProvider(); this.createProviders(userStorageUri); const readyPromises: Promise[] = []; for (const provider of this.providers.values()) { readyPromises.push(provider.ready.catch(e => this.logger.error(e))); } Promise.all(readyPromises).then(() => this._ready.resolve()); } protected createProviders(userStorageLocation: URI): void { for (const configName of [...this.configurations.getSectionNames(), this.configurations.getConfigName()]) { const sectionUri = userStorageLocation.resolve(configName + '.json'); const sectionKey = sectionUri.toString(); if (!this.providers.has(sectionKey)) { const provider = this.createProvider(sectionUri, configName); this.providers.set(sectionKey, provider); } } } override getConfigUri(resourceUri?: string, sectionName: string = this.configurations.getConfigName()): URI | undefined { for (const provider of this.providers.values()) { const configUri = provider.getConfigUri(resourceUri); if (configUri && this.configurations.getName(configUri) === sectionName) { return configUri; } } return undefined; } override resolve(preferenceName: string, resourceUri?: string): PreferenceResolveResult { const result: PreferenceResolveResult = {}; for (const provider of this.providers.values()) { const { value, configUri } = provider.resolve(preferenceName, resourceUri); if (configUri && value !== undefined) { result.configUri = configUri; result.value = PreferenceUtils.merge(result.value as any, value as any) as any; } } return result; } getPreferences(resourceUri?: string): { [p: string]: any } { let result = {}; for (const provider of this.providers.values()) { const preferences = provider.getPreferences(); result = PreferenceUtils.merge(result, preferences) as any; } return result; } async setPreference(preferenceName: string, value: any, resourceUri?: string): Promise { const sectionName = preferenceName.split('.', 1)[0]; const defaultConfigName = this.configurations.getConfigName(); const configName = this.configurations.isSectionName(sectionName) ? sectionName : defaultConfigName; const setWithConfigName = async (name: string): Promise => { for (const provider of this.providers.values()) { if (this.configurations.getName(provider.getConfigUri()) === name) { if (await provider.setPreference(preferenceName, value, resourceUri)) { return true; } } } return false; }; if (await setWithConfigName(configName)) { // Try in the section we believe it belongs in. return true; } else if (configName !== defaultConfigName) { // Fall back to `settings.json` if that fails. return setWithConfigName(defaultConfigName); } return false; } protected createProvider(uri: URI, sectionName: string): UserPreferenceProvider { const provider = this.providerFactory(uri, sectionName); this.toDispose.push(provider); this.toDispose.push(provider.onDidPreferencesChanged(change => this.onDidPreferencesChangedEmitter.fire(change))); return provider; } }