'use strict'; import { commands, ConfigurationChangeEvent, Disposable, ExtensionContext, Uri } from 'vscode'; import { FileAnnotationController } from './annotations/fileAnnotationController'; import { LineAnnotationController } from './annotations/lineAnnotationController'; import { GitCodeLensController } from './codelens/codeLensController'; import { Commands, ToggleFileBlameCommandArgs } from './commands'; import { AnnotationsToggleMode, Config, configuration, ConfigurationWillChangeEvent } from './configuration'; import { GitFileSystemProvider } from './git/fsProvider'; import { GitService } from './git/gitService'; import { clearAvatarCache } from './avatars'; import { LineHoverController } from './hovers/lineHoverController'; import { Keyboard } from './keyboard'; import { Logger } from './logger'; import { StatusBarController } from './statusbar/statusBarController'; import { GitDocumentTracker } from './trackers/gitDocumentTracker'; import { GitLineTracker } from './trackers/gitLineTracker'; import { CompareView } from './views/compareView'; import { FileHistoryView } from './views/fileHistoryView'; import { LineHistoryView } from './views/lineHistoryView'; import { RepositoriesView } from './views/repositoriesView'; import { SearchView } from './views/searchView'; import { ViewCommands } from './views/viewCommands'; import { VslsController } from './vsls/vsls'; import { SettingsWebview } from './webviews/settingsWebview'; import { WelcomeWebview } from './webviews/welcomeWebview'; export class Container { private static _configsAffectedByMode: string[] | undefined; private static _applyModeConfigurationTransformBound: | ((e: ConfigurationChangeEvent) => ConfigurationChangeEvent) | undefined; static initialize(context: ExtensionContext, config: Config) { this._context = context; this._config = Container.applyMode(config); context.subscriptions.push((this._lineTracker = new GitLineTracker())); context.subscriptions.push((this._tracker = new GitDocumentTracker())); context.subscriptions.push((this._vsls = new VslsController())); context.subscriptions.push((this._git = new GitService())); // Since there is a bit of a chicken & egg problem with the DocumentTracker and the GitService, initialize the tracker once the GitService is loaded this._tracker.initialize(); context.subscriptions.push((this._fileAnnotationController = new FileAnnotationController())); context.subscriptions.push((this._lineAnnotationController = new LineAnnotationController())); context.subscriptions.push((this._lineHoverController = new LineHoverController())); context.subscriptions.push((this._statusBarController = new StatusBarController())); context.subscriptions.push((this._codeLensController = new GitCodeLensController())); context.subscriptions.push((this._keyboard = new Keyboard())); context.subscriptions.push((this._settingsWebview = new SettingsWebview())); context.subscriptions.push((this._welcomeWebview = new WelcomeWebview())); if (config.views.compare.enabled) { context.subscriptions.push((this._compareView = new CompareView())); } else { let disposable: Disposable; // eslint-disable-next-line prefer-const disposable = configuration.onDidChange(e => { if (configuration.changed(e, 'views', 'compare', 'enabled')) { disposable.dispose(); context.subscriptions.push((this._compareView = new CompareView())); } }); } if (config.views.fileHistory.enabled) { context.subscriptions.push((this._fileHistoryView = new FileHistoryView())); } else { let disposable: Disposable; // eslint-disable-next-line prefer-const disposable = configuration.onDidChange(e => { if (configuration.changed(e, 'views', 'fileHistory', 'enabled')) { disposable.dispose(); context.subscriptions.push((this._fileHistoryView = new FileHistoryView())); } }); } if (config.views.lineHistory.enabled) { context.subscriptions.push((this._lineHistoryView = new LineHistoryView())); } else { let disposable: Disposable; // eslint-disable-next-line prefer-const disposable = configuration.onDidChange(e => { if (configuration.changed(e, 'views', 'lineHistory', 'enabled')) { disposable.dispose(); context.subscriptions.push((this._lineHistoryView = new LineHistoryView())); } }); } if (config.views.repositories.enabled) { context.subscriptions.push((this._repositoriesView = new RepositoriesView())); } else { let disposable: Disposable; // eslint-disable-next-line prefer-const disposable = configuration.onDidChange(e => { if (configuration.changed(e, 'views', 'repositories', 'enabled')) { disposable.dispose(); context.subscriptions.push((this._repositoriesView = new RepositoriesView())); } }); } if (config.views.search.enabled) { context.subscriptions.push((this._searchView = new SearchView())); } else { let disposable: Disposable; // eslint-disable-next-line prefer-const disposable = configuration.onDidChange(e => { if (configuration.changed(e, 'views', 'search', 'enabled')) { disposable.dispose(); context.subscriptions.push((this._searchView = new SearchView())); } }); } context.subscriptions.push(new GitFileSystemProvider()); context.subscriptions.push(configuration.onWillChange(this.onConfigurationChanging, this)); } private static onConfigurationChanging(e: ConfigurationWillChangeEvent) { this._config = undefined; if (configuration.changed(e.change, 'outputLevel')) { Logger.level = configuration.get('outputLevel'); } if (configuration.changed(e.change, 'defaultGravatarsStyle')) { clearAvatarCache(); } if (configuration.changed(e.change, 'mode') || configuration.changed(e.change, 'modes')) { if (this._applyModeConfigurationTransformBound === undefined) { this._applyModeConfigurationTransformBound = this.applyModeConfigurationTransform.bind(this); } e.transform = this._applyModeConfigurationTransformBound; } } private static _codeLensController: GitCodeLensController; static get codeLens() { return this._codeLensController; } private static _compareView: CompareView | undefined; static get compareView() { if (this._compareView === undefined) { this._context.subscriptions.push((this._compareView = new CompareView())); } return this._compareView; } private static _config: Config | undefined; static get config() { if (this._config === undefined) { this._config = Container.applyMode(configuration.get()); } return this._config; } private static _context: ExtensionContext; static get context() { return this._context; } private static _fileAnnotationController: FileAnnotationController; static get fileAnnotations() { return this._fileAnnotationController; } private static _fileHistoryView: FileHistoryView | undefined; static get fileHistoryView() { if (this._fileHistoryView === undefined) { this._context.subscriptions.push((this._fileHistoryView = new FileHistoryView())); } return this._fileHistoryView; } private static _git: GitService; static get git() { return this._git; } private static _keyboard: Keyboard; static get keyboard() { return this._keyboard; } private static _lineAnnotationController: LineAnnotationController; static get lineAnnotations() { return this._lineAnnotationController; } private static _lineHistoryView: LineHistoryView | undefined; static get lineHistoryView() { if (this._lineHistoryView === undefined) { this._context.subscriptions.push((this._lineHistoryView = new LineHistoryView())); } return this._lineHistoryView; } private static _lineHoverController: LineHoverController; static get lineHovers() { return this._lineHoverController; } private static _lineTracker: GitLineTracker; static get lineTracker() { return this._lineTracker; } private static _repositoriesView: RepositoriesView | undefined; static get repositoriesView(): RepositoriesView { if (this._repositoriesView === undefined) { this._context.subscriptions.push((this._repositoriesView = new RepositoriesView())); } return this._repositoriesView; } private static _searchView: SearchView | undefined; static get searchView() { if (this._searchView === undefined) { this._context.subscriptions.push((this._searchView = new SearchView())); } return this._searchView; } private static _settingsWebview: SettingsWebview; static get settingsWebview() { return this._settingsWebview; } private static _statusBarController: StatusBarController; static get statusBar() { return this._statusBarController; } private static _tracker: GitDocumentTracker; static get tracker() { return this._tracker; } private static _viewCommands: ViewCommands | undefined; static get viewCommands() { if (this._viewCommands === undefined) { this._viewCommands = new ViewCommands(); } return this._viewCommands; } private static _vsls: VslsController; static get vsls() { return this._vsls; } private static _welcomeWebview: WelcomeWebview; static get welcomeWebview() { return this._welcomeWebview; } private static applyMode(config: Config) { if (!config.mode.active) return config; const mode = config.modes[config.mode.active]; if (mode == null) return config; if (mode.annotations != null) { let command: string | undefined; switch (mode.annotations) { case 'blame': config.blame.toggleMode = AnnotationsToggleMode.Window; command = Commands.ToggleFileBlame; break; case 'heatmap': config.heatmap.toggleMode = AnnotationsToggleMode.Window; command = Commands.ToggleFileHeatmap; break; case 'recentChanges': config.recentChanges.toggleMode = AnnotationsToggleMode.Window; command = Commands.ToggleFileRecentChanges; break; } if (command !== undefined) { const commandArgs: ToggleFileBlameCommandArgs = { on: true }; // Make sure to delay the execution by a bit so that the configuration changes get propegated first setTimeout(() => commands.executeCommand(command!, commandArgs), 50); } } if (mode.codeLens != null) { config.codeLens.enabled = mode.codeLens; } if (mode.currentLine != null) { config.currentLine.enabled = mode.currentLine; } if (mode.hovers != null) { config.hovers.enabled = mode.hovers; } if (mode.statusBar != null) { config.statusBar.enabled = mode.statusBar; } if (mode.views != null) { config.views.compare.enabled = mode.views; } if (mode.views != null) { config.views.fileHistory.enabled = mode.views; } if (mode.views != null) { config.views.lineHistory.enabled = mode.views; } if (mode.views != null) { config.views.repositories.enabled = mode.views; } if (mode.views != null) { config.views.search.enabled = mode.views; } return config; } private static applyModeConfigurationTransform(e: ConfigurationChangeEvent): ConfigurationChangeEvent { if (this._configsAffectedByMode === undefined) { this._configsAffectedByMode = [ `gitlens.${configuration.name('mode')}`, `gitlens.${configuration.name('modes')}`, `gitlens.${configuration.name('blame', 'toggleMode')}`, `gitlens.${configuration.name('codeLens')}`, `gitlens.${configuration.name('currentLine')}`, `gitlens.${configuration.name('heatmap', 'toggleMode')}`, `gitlens.${configuration.name('hovers')}`, `gitlens.${configuration.name('recentChanges', 'toggleMode')}`, `gitlens.${configuration.name('statusBar')}`, `gitlens.${configuration.name('views', 'compare')}`, `gitlens.${configuration.name('views', 'fileHistory')}`, `gitlens.${configuration.name('views', 'lineHistory')}`, `gitlens.${configuration.name('views', 'repositories')}`, `gitlens.${configuration.name('views', 'search')}` ]; } const original = e.affectsConfiguration; return { ...e, affectsConfiguration: (section: string, resource?: Uri) => { if (this._configsAffectedByMode && this._configsAffectedByMode.some(n => section.startsWith(n))) { return true; } return original(section, resource); } }; } }