From 79ad799511feb0bccebbf2e388052ad15d101d57 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 5 Feb 2017 14:32:04 -0500 Subject: [PATCH] Fixes whitespace toggling --- package.json | 8 +-- src/blameAnnotationController.ts | 44 +++------------- src/blameAnnotationProvider.ts | 26 +++------- src/whitespaceController.ts | 106 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 58 deletions(-) create mode 100644 src/whitespaceController.ts diff --git a/package.json b/package.json index e544e9f..47d44d4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ }, "publisher": "eamodio", "engines": { - "vscode": "^1.7.0" + "vscode": "^1.9.0" }, "license": "SEE LICENSE IN LICENSE", "displayName": "GitLens", @@ -419,11 +419,11 @@ "tmp": "^0.0.31" }, "devDependencies": { - "@types/node": "^6.0.55", - "@types/mocha": "^2.2.37", + "@types/node": "^7.0.5", + "@types/mocha": "^2.2.39", "@types/tmp": "^0.0.32", "mocha": "^3.2.0", - "tslint": "^4.3.1", + "tslint": "^4.4.2", "typescript": "^2.1.5", "vscode": "^1.0.3" } diff --git a/src/blameAnnotationController.ts b/src/blameAnnotationController.ts index 6d1d433..a74eb72 100644 --- a/src/blameAnnotationController.ts +++ b/src/blameAnnotationController.ts @@ -1,23 +1,24 @@ 'use strict'; import { Functions, IDeferred } from './system'; -import { commands, Disposable, ExtensionContext, TextDocument, TextEditor, TextEditorViewColumnChangeEvent, window, workspace } from 'vscode'; +import { Disposable, ExtensionContext, TextDocument, TextEditor, TextEditorViewColumnChangeEvent, window, workspace } from 'vscode'; import { BlameAnnotationProvider } from './blameAnnotationProvider'; import { TextDocumentComparer, TextEditorComparer } from './comparers'; -import { BuiltInCommands } from './constants'; import GitProvider from './gitProvider'; import { Logger } from './logger'; +import WhitespaceController from './whitespaceController'; export default class BlameAnnotationController extends Disposable { private _annotationProviders: Map = new Map(); private _blameAnnotationsDisposable: Disposable; - private _pendingWhitespaceToggleDisposable: Disposable; private _pendingClearAnnotations: Map void) & IDeferred> = new Map(); - private _pendingWhitespaceToggles: Set = new Set(); private _visibleColumns: Set; + private _whitespaceController: WhitespaceController; constructor(private context: ExtensionContext, private git: GitProvider) { super(() => this.dispose()); + + this._whitespaceController = new WhitespaceController(context); } dispose() { @@ -27,7 +28,7 @@ export default class BlameAnnotationController extends Disposable { this._annotationProviders.forEach(async (p, i) => await this.clear(i)); this._blameAnnotationsDisposable && this._blameAnnotationsDisposable.dispose(); - this._pendingWhitespaceToggleDisposable && this._pendingWhitespaceToggleDisposable.dispose(); + this._whitespaceController && this._whitespaceController.dispose(); } async clear(column: number, toggleRenderWhitespace: boolean = true) { @@ -54,7 +55,7 @@ export default class BlameAnnotationController extends Disposable { return true; } - const provider = new BlameAnnotationProvider(this.context, this.git, editor); + const provider = new BlameAnnotationProvider(this.context, this.git, this._whitespaceController, editor); if (!await provider.supportsBlame()) return false; if (currentProvider) { @@ -99,27 +100,6 @@ export default class BlameAnnotationController extends Disposable { return set; } - private _onActiveTextEditorChanged(e: TextEditor) { - if (this._pendingWhitespaceToggles.size === 0 || (e.viewColumn === undefined && !this.git.hasGitUriForFile(e))) return; - - const viewColumn = e.viewColumn || -1; - - if (this._pendingWhitespaceToggles.has(viewColumn)) { - Logger.log('ActiveTextEditorChanged:', `Remove pending whitespace toggle for column ${viewColumn}`); - this._pendingWhitespaceToggles.delete(viewColumn); - - // HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- toggle whitespace back on - Logger.log('ActiveTextEditorChanged:', `Toggle whitespace rendering on`); - commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace); - } - - if (this._pendingWhitespaceToggles.size === 0) { - Logger.log('ActiveTextEditorChanged:', `Remove listener registrations for pending whitespace toggles`); - this._pendingWhitespaceToggleDisposable.dispose(); - this._pendingWhitespaceToggleDisposable = undefined; - } - } - private _onTextDocumentClosed(e: TextDocument) { for (const [key, p] of this._annotationProviders) { if (!TextDocumentComparer.equals(p.document, e)) continue; @@ -174,16 +154,8 @@ export default class BlameAnnotationController extends Disposable { Logger.log('VisibleTextEditorsChanged:', `Clear blame annotations for column ${key}`); const editor = window.activeTextEditor; - if (p.requiresRenderWhitespaceToggle && (editor && (editor.viewColumn || -1) !== key)) { + if (editor && (editor.viewColumn || -1) !== key) { this.clear(key, false); - - if (!this._pendingWhitespaceToggleDisposable) { - Logger.log('VisibleTextEditorsChanged:', `Add listener registrations for pending whitespace toggles`); - this._pendingWhitespaceToggleDisposable = window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this); - } - - Logger.log('VisibleTextEditorsChanged:', `Add pending whitespace toggle for column ${key}`); - this._pendingWhitespaceToggles.add(key); } else { this.clear(key); diff --git a/src/blameAnnotationProvider.ts b/src/blameAnnotationProvider.ts index 3fec35b..71ca605 100644 --- a/src/blameAnnotationProvider.ts +++ b/src/blameAnnotationProvider.ts @@ -1,11 +1,12 @@ 'use strict'; import { Iterables } from './system'; -import { commands, DecorationOptions, Disposable, ExtensionContext, OverviewRulerLane, Range, TextDocument, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode'; +import { DecorationOptions, Disposable, ExtensionContext, OverviewRulerLane, Range, TextDocument, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode'; import { TextDocumentComparer } from './comparers'; import { BlameAnnotationStyle, IBlameConfig } from './configuration'; -import { BuiltInCommands } from './constants'; +// import { BuiltInCommands } from './constants'; import GitProvider, { GitCommit, GitUri, IGitBlame } from './gitProvider'; import { Logger } from './logger'; +import WhitespaceController from './whitespaceController'; import * as moment from 'moment'; const blameDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({ @@ -19,14 +20,13 @@ let highlightDecoration: TextEditorDecorationType; export class BlameAnnotationProvider extends Disposable { public document: TextDocument; - public requiresRenderWhitespaceToggle: boolean = false; private _blame: Promise; private _config: IBlameConfig; private _disposable: Disposable; private _uri: GitUri; - constructor(context: ExtensionContext, private git: GitProvider, public editor: TextEditor) { + constructor(context: ExtensionContext, private git: GitProvider, private whitespaceController: WhitespaceController, public editor: TextEditor) { super(() => this.dispose()); if (!highlightDecoration) { @@ -56,12 +56,9 @@ export class BlameAnnotationProvider extends Disposable { const subscriptions: Disposable[] = []; - subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this)); subscriptions.push(window.onDidChangeTextEditorSelection(this._onActiveSelectionChanged, this)); this._disposable = Disposable.from(...subscriptions); - - this._onConfigurationChanged(); } async dispose(toggleRenderWhitespace: boolean = true) { @@ -71,19 +68,14 @@ export class BlameAnnotationProvider extends Disposable { } // HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- toggle whitespace back on - if (toggleRenderWhitespace && this.requiresRenderWhitespaceToggle) { + if (toggleRenderWhitespace) { Logger.log('BlameAnnotationProvider.dispose:', `Toggle whitespace rendering on`); - await commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace); + await this.whitespaceController.restore(); } this._disposable && this._disposable.dispose(); } - private _onConfigurationChanged() { - const renderWhitespace = workspace.getConfiguration('editor').get('renderWhitespace'); - this.requiresRenderWhitespaceToggle = !(renderWhitespace == null || renderWhitespace === 'none'); - } - private async _onActiveSelectionChanged(e: TextEditorSelectionChangeEvent) { if (!TextDocumentComparer.equals(this.document, e.textEditor && e.textEditor.document)) return; @@ -100,10 +92,8 @@ export class BlameAnnotationProvider extends Disposable { if (!blame || !blame.lines.length) return false; // HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- toggle whitespace off - if (this.requiresRenderWhitespaceToggle) { - Logger.log('BlameAnnotationProvider.provideBlameAnnotation:', `Toggle whitespace rendering off`); - await commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace); - } + Logger.log('BlameAnnotationProvider.provideBlameAnnotation:', `Toggle whitespace rendering off`); + await this.whitespaceController.override(); let blameDecorationOptions: DecorationOptions[] | undefined; switch (this._config.annotation.style) { diff --git a/src/whitespaceController.ts b/src/whitespaceController.ts new file mode 100644 index 0000000..2a9a3a2 --- /dev/null +++ b/src/whitespaceController.ts @@ -0,0 +1,106 @@ +'use strict'; +import { Disposable, ExtensionContext, workspace } from 'vscode'; +import { Logger } from './logger'; + +enum SettingLocation { + workspace, + global, + default +} + +export default class WhitespaceController extends Disposable { + + private _count: number = 0; + private _disposable: Disposable; + private _ignoreNextConfigChange: boolean = false; + private _renderWhitespace: string; + private _renderWhitespaceLocation: SettingLocation = SettingLocation.default; + private _requiresOverride: boolean; + + constructor(context: ExtensionContext) { + super(() => this.dispose()); + + const subscriptions: Disposable[] = []; + + subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this)); + + this._disposable = Disposable.from(...subscriptions); + + this._onConfigurationChanged(); + } + + dispose() { + if (this._count !== 0) { + this._restoreWhitespace(); + } + } + + private _onConfigurationChanged() { + if (this._ignoreNextConfigChange) { + this._ignoreNextConfigChange = false; + Logger.log(`Whitespace changed; ignored`); + + 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(); + } + } + } + + override() { + Logger.log(`Request whitespace override; count=${this._count}`); + if (this._count === 0 && this._requiresOverride) { + this._ignoreNextConfigChange = true; + // Override whitespace (turn off) + this._overrideWhitespace(); + } + this._count++; + } + + private _overrideWhitespace() { + Logger.log(`Override whitespace`); + const config = workspace.getConfiguration('editor'); + config.update('renderWhitespace', 'none', this._renderWhitespaceLocation === SettingLocation.global); + } + + restore() { + Logger.log(`Request whitespace restore; count=${this._count}`); + this._count--; + if (this._count === 0 && this._requiresOverride) { + // restore whitespace + this._restoreWhitespace(); + } + } + + private _restoreWhitespace() { + Logger.log(`Restore whitespace`); + const config = workspace.getConfiguration('editor'); + config.update('renderWhitespace', + this._renderWhitespaceLocation === SettingLocation.default + ? undefined + : this._renderWhitespace, + this._renderWhitespaceLocation === SettingLocation.global); + } +} \ No newline at end of file