'use strict'; export * from './ui/config'; import { ConfigurationChangeEvent, ConfigurationTarget, Event, EventEmitter, ExtensionContext, Uri, workspace } from 'vscode'; import { CommandContext, extensionId, setCommandContext } from './constants'; import { Container } from './container'; import { clearGravatarCache } from './git/gitService'; import { Functions } from './system'; import { Config, KeyMap } from './ui/config'; const emptyConfig: any = new Proxy({} as Config, { get(target, propKey, receiver) { return emptyConfig; } }); export class Configuration { static configure(context: ExtensionContext) { context.subscriptions.push( workspace.onDidChangeConfiguration(configuration.onConfigurationChanged, configuration) ); } private _onDidChange = new EventEmitter(); get onDidChange(): Event { return this._onDidChange.event; } private readonly _configAffectedByMode: string[]; constructor() { this._configAffectedByMode = [ `gitlens.${this.name('mode').value}`, `gitlens.${this.name('modes').value}`, `gitlens.${this.name('codeLens').value}`, `gitlens.${this.name('currentLine').value}`, `gitlens.${this.name('fileHistoryExplorer').value}`, `gitlens.${this.name('hovers').value}`, `gitlens.${this.name('lineHistoryExplorer').value}`, `gitlens.${this.name('repositoriesExplorer').value}`, `gitlens.${this.name('statusBar').value}` ]; } private onConfigurationChanged(e: ConfigurationChangeEvent) { if (!e.affectsConfiguration(extensionId, null!)) return; Container.resetConfig(); if (configuration.changed(e, configuration.name('defaultGravatarsStyle').value)) { clearGravatarCache(); } const section = configuration.name('keymap').value; if (configuration.changed(e, section)) { setCommandContext(CommandContext.KeyMap, this.get(section)); } if ( configuration.changed(e, configuration.name('mode').value) || configuration.changed(e, configuration.name('modes').value) ) { const original = e.affectsConfiguration; e = { ...e, affectsConfiguration: (section: string, resource?: Uri) => { if (this._configAffectedByMode.some(n => section.startsWith(n))) { return true; } return original(section, resource); } } as ConfigurationChangeEvent; } this._onDidChange.fire(e); } readonly initializingChangeEvent: ConfigurationChangeEvent = { affectsConfiguration: (section: string, resource?: Uri) => false }; get(section?: string, resource?: Uri | null, defaultValue?: T) { return defaultValue === undefined ? workspace .getConfiguration(section === undefined ? undefined : extensionId, resource!) .get(section === undefined ? extensionId : section)! : workspace .getConfiguration(section === undefined ? undefined : extensionId, resource!) .get(section === undefined ? extensionId : section, defaultValue)!; } changed(e: ConfigurationChangeEvent, section: string, resource?: Uri | null) { return e.affectsConfiguration(`${extensionId}.${section}`, resource!); } initializing(e: ConfigurationChangeEvent) { return e === this.initializingChangeEvent; } inspect(section?: string, resource?: Uri | null) { return workspace .getConfiguration(section === undefined ? undefined : extensionId, resource!) .inspect(section === undefined ? extensionId : section); } async migrate( from: string, to: string, options: { fallbackValue?: TTo; migrationFn?(value: TFrom): TTo } = {} ): Promise { const inspection = configuration.inspect(from); if (inspection === undefined) return false; let migrated = false; if (inspection.globalValue !== undefined) { await this.update( to, options.migrationFn ? options.migrationFn(inspection.globalValue as TFrom) : inspection.globalValue, ConfigurationTarget.Global ); migrated = true; // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.Global); // } // catch { } // } } if (inspection.workspaceValue !== undefined) { await this.update( to, options.migrationFn ? options.migrationFn(inspection.workspaceValue as TFrom) : inspection.workspaceValue, ConfigurationTarget.Workspace ); migrated = true; // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.Workspace); // } // catch { } // } } if (inspection.workspaceFolderValue !== undefined) { await this.update( to, options.migrationFn ? options.migrationFn(inspection.workspaceFolderValue as TFrom) : inspection.workspaceFolderValue, ConfigurationTarget.WorkspaceFolder ); migrated = true; // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.WorkspaceFolder); // } // catch { } // } } if (!migrated && options.fallbackValue !== undefined) { await this.update(to, options.fallbackValue, ConfigurationTarget.Global); migrated = true; } return migrated; } async migrateIfMissing(from: string, to: string, options: { migrationFn?(value: TFrom): TTo } = {}) { const fromInspection = configuration.inspect(from); if (fromInspection === undefined) return; const toInspection = configuration.inspect(to); if (fromInspection.globalValue !== undefined) { if (toInspection === undefined || toInspection.globalValue === undefined) { await this.update( to, options.migrationFn ? options.migrationFn(fromInspection.globalValue as TFrom) : fromInspection.globalValue, ConfigurationTarget.Global ); // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.Global); // } // catch { } // } } } if (fromInspection.workspaceValue !== undefined) { if (toInspection === undefined || toInspection.workspaceValue === undefined) { await this.update( to, options.migrationFn ? options.migrationFn(fromInspection.workspaceValue as TFrom) : fromInspection.workspaceValue, ConfigurationTarget.Workspace ); // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.Workspace); // } // catch { } // } } } if (fromInspection.workspaceFolderValue !== undefined) { if (toInspection === undefined || toInspection.workspaceFolderValue === undefined) { await this.update( to, options.migrationFn ? options.migrationFn(fromInspection.workspaceFolderValue as TFrom) : fromInspection.workspaceFolderValue, ConfigurationTarget.WorkspaceFolder ); // Can't delete the old setting currently because it errors with `Unable to write to User Settings because is not a registered configuration` // if (from !== to) { // try { // await this.update(from, undefined, ConfigurationTarget.WorkspaceFolder); // } // catch { } // } } } } name(name: K) { return Functions.propOf(emptyConfig as Config, name); } update(section: string, value: any, target: ConfigurationTarget, resource?: Uri | null) { return workspace .getConfiguration(extensionId, target === ConfigurationTarget.Global ? undefined : resource!) .update(section, value, target); } async updateEffective(section: string, value: any, resource: Uri | null = null) { const inspect = await configuration.inspect(section, resource)!; if (inspect.workspaceFolderValue !== undefined) { if (value === inspect.workspaceFolderValue) return; return await configuration.update(section, value, ConfigurationTarget.WorkspaceFolder, resource); } if (inspect.workspaceValue !== undefined) { if (value === inspect.workspaceValue) return; return await configuration.update(section, value, ConfigurationTarget.Workspace); } if (inspect.globalValue === value || (inspect.globalValue === undefined && value === inspect.defaultValue)) { return; } return await configuration.update( section, value === inspect.defaultValue ? undefined : value, ConfigurationTarget.Global ); } } export const configuration = new Configuration();