diff --git a/src/blameAnnotationProvider.ts b/src/blameAnnotationProvider.ts index 5d90057..e033729 100644 --- a/src/blameAnnotationProvider.ts +++ b/src/blameAnnotationProvider.ts @@ -63,12 +63,23 @@ export class BlameAnnotationProvider extends Disposable { } async provideBlameAnnotation(shaOrLine?: string | number): Promise { - const blame = await this._blame; - if (!blame || !blame.lines.length) return false; - + let whitespacePromise: Promise; // HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- override whitespace (turn off) if (this._config.annotation.style !== BlameAnnotationStyle.Trailing) { - this.whitespaceController && await this.whitespaceController.override(); + whitespacePromise = this.whitespaceController && this.whitespaceController.override(); + } + + let blame: IGitBlame; + if (whitespacePromise) { + [blame] = await Promise.all([this._blame, whitespacePromise]); + } + else { + blame = await this._blame; + } + + if (!blame || !blame.lines.length) { + this.whitespaceController && await this.whitespaceController.restore(); + return false; } let blameDecorationOptions: DecorationOptions[] | undefined; diff --git a/src/whitespaceController.ts b/src/whitespaceController.ts index b172415..485e754 100644 --- a/src/whitespaceController.ts +++ b/src/whitespaceController.ts @@ -2,21 +2,77 @@ import { Disposable, workspace } from 'vscode'; import { Logger } from './logger'; +interface ConfigurationInspection { + key: string; + defaultValue?: string; + globalValue?: string; + workspaceValue?: string; +} + enum SettingLocation { workspace, global, default } +class RenderWhitespaceConfiguration { + + constructor(public inspection: ConfigurationInspection) { } + + get location(): SettingLocation { + if (this.inspection.workspaceValue) return SettingLocation.workspace; + if (this.inspection.globalValue) return SettingLocation.global; + return SettingLocation.default; + } + + get overrideRequired() { + return this.value != null && this.value !== 'none'; + } + + get value(): string { + return this.inspection.workspaceValue || this.inspection.globalValue || this.inspection.defaultValue; + } + + update(replacement: ConfigurationInspection): boolean { + let override = false; + + switch (this.location) { + case SettingLocation.workspace: + this.inspection.defaultValue = replacement.defaultValue; + this.inspection.globalValue = replacement.globalValue; + if (replacement.workspaceValue !== 'none') { + this.inspection.workspaceValue = replacement.workspaceValue; + override = true; + } + break; + case SettingLocation.global: + this.inspection.defaultValue = replacement.defaultValue; + this.inspection.workspaceValue = replacement.workspaceValue; + if (replacement.globalValue !== 'none') { + this.inspection.globalValue = replacement.globalValue; + override = true; + } + break; + case SettingLocation.default: + this.inspection.globalValue = replacement.globalValue; + this.inspection.workspaceValue = replacement.workspaceValue; + if (replacement.defaultValue !== 'none') { + this.inspection.defaultValue = replacement.defaultValue; + override = true; + } + break; + } + + return override; + } +} + export class WhitespaceController extends Disposable { + private _configuration: RenderWhitespaceConfiguration; private _count: number = 0; private _disposable: Disposable; private _disposed: boolean = false; - private _ignoreNextConfigChange: boolean = false; - private _renderWhitespace: string; - private _renderWhitespaceLocation: SettingLocation = SettingLocation.default; - private _requiresOverride: boolean; constructor() { super(() => this.dispose()); @@ -30,10 +86,10 @@ export class WhitespaceController extends Disposable { this._onConfigurationChanged(); } - dispose() { + async dispose() { this._disposed = true; if (this._count !== 0) { - this._restoreWhitespace(); + await this._restoreWhitespace(); this._count = 0; } } @@ -41,75 +97,56 @@ export class WhitespaceController extends Disposable { private _onConfigurationChanged() { if (this._disposed) return; - if (this._ignoreNextConfigChange) { - this._ignoreNextConfigChange = false; - Logger.log(`Whitespace changed; ignored`); + const inspection = workspace.getConfiguration('editor').inspect('renderWhitespace'); + if (!this._count) { + this._configuration = new RenderWhitespaceConfiguration(inspection); return; } - const config = workspace.getConfiguration('editor'); - const inspection = config.inspect('renderWhitespace'); - - if (inspection.workspaceValue) { - this._renderWhitespace = inspection.workspaceValue; - this._renderWhitespaceLocation = SettingLocation.workspace; - } - else if (inspection.globalValue) { - this._renderWhitespace = inspection.globalValue; - this._renderWhitespaceLocation = SettingLocation.global; - } - else { - this._renderWhitespace = inspection.defaultValue; - this._renderWhitespaceLocation = SettingLocation.default; - } - - Logger.log(`Whitespace changed; renderWhitespace=${this._renderWhitespace}, location=${this._renderWhitespaceLocation}`); - this._requiresOverride = !(this._renderWhitespace == null || this._renderWhitespace === 'none'); - if (this._requiresOverride) { - if (this._count !== 0) { - // Since we were currently overriding whitespace, re-override - this._overrideWhitespace(); - } + if (this._configuration.update(inspection)) { + // Since we were currently overriding whitespace, re-override + setTimeout(() => this._overrideWhitespace(), 1); } } - override() { + async override() { if (this._disposed) return; Logger.log(`Request whitespace override; count=${this._count}`); - if (this._count === 0 && this._requiresOverride) { - this._ignoreNextConfigChange = true; + this._count++; + if (this._count === 1 && this._configuration.overrideRequired) { // Override whitespace (turn off) - this._overrideWhitespace(); + await this._overrideWhitespace(); + // Add a delay to give the editor time to turn off the whitespace + await new Promise((resolve, reject) => setTimeout(resolve, 250)); } - this._count++; } - private _overrideWhitespace() { + private async _overrideWhitespace() { Logger.log(`Override whitespace`); const config = workspace.getConfiguration('editor'); - config.update('renderWhitespace', 'none', this._renderWhitespaceLocation === SettingLocation.global); + return config.update('renderWhitespace', 'none', this._configuration.location === SettingLocation.global); } - restore() { + async restore() { if (this._disposed || this._count === 0) return; Logger.log(`Request whitespace restore; count=${this._count}`); this._count--; - if (this._count === 0 && this._requiresOverride) { + if (this._count === 0 && this._configuration.overrideRequired) { // restore whitespace - this._restoreWhitespace(); + await this._restoreWhitespace(); } } - private _restoreWhitespace() { + private async _restoreWhitespace() { Logger.log(`Restore whitespace`); const config = workspace.getConfiguration('editor'); - config.update('renderWhitespace', - this._renderWhitespaceLocation === SettingLocation.default + return config.update('renderWhitespace', + this._configuration.location === SettingLocation.default ? undefined - : this._renderWhitespace, - this._renderWhitespaceLocation === SettingLocation.global); + : this._configuration.value, + this._configuration.location === SettingLocation.global); } } \ No newline at end of file