You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

100 lines
3.6 KiB

'use strict';
import { Disposable, Event, EventEmitter, TextDocument, TextDocumentChangeEvent, TextEditor, window, workspace } from 'vscode';
import { CommandContext, setCommandContext } from './commands';
import { TextDocumentComparer } from './comparers';
import { GitService } from './gitService';
export interface BlameabilityChangeEvent {
blameable: boolean;
editor: TextEditor;
}
export class BlameabilityTracker extends Disposable {
private _onDidChange = new EventEmitter<BlameabilityChangeEvent>();
get onDidChange(): Event<BlameabilityChangeEvent> {
return this._onDidChange.event;
}
private _disposable: Disposable;
private _documentChangeDisposable: Disposable;
private _editor: TextEditor;
private _isBlameable: boolean;
constructor(private git: GitService) {
super(() => this.dispose());
const subscriptions: Disposable[] = [];
subscriptions.push(window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this));
subscriptions.push(workspace.onDidSaveTextDocument(this._onTextDocumentSaved, this));
subscriptions.push(this.git.onDidBlameFail(this._onBlameFailed, this));
this._disposable = Disposable.from(...subscriptions);
this._onActiveTextEditorChanged(window.activeTextEditor);
}
dispose() {
this._disposable && this._disposable.dispose();
this._documentChangeDisposable && this._documentChangeDisposable.dispose();
}
private _onActiveTextEditorChanged(editor: TextEditor) {
this._editor = editor;
let blameable = editor && editor.document && !editor.document.isDirty;
if (blameable) {
blameable = this.git.getBlameability(editor.document.fileName);
}
this._subscribeToDocumentChanges();
this.updateBlameability(blameable, true);
}
private _onBlameFailed(key: string) {
const fileName = this._editor && this._editor.document && this._editor.document.fileName;
if (!fileName || key !== this.git.getCacheEntryKey(fileName)) return;
this.updateBlameability(false);
}
private _onTextDocumentChanged(e: TextDocumentChangeEvent) {
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e && e.document)) return;
// Can't unsubscribe here because undo doesn't trigger any other event
//this._unsubscribeToDocumentChanges();
//this.updateBlameability(false);
// We have to defer because isDirty is not reliable inside this event
setTimeout(() => this.updateBlameability(!e.document.isDirty), 1);
}
private _onTextDocumentSaved(e: TextDocument) {
if (!TextDocumentComparer.equals(this._editor && this._editor.document, e)) return;
// Don't need to resubscribe as we aren't unsubscribing on document changes anymore
//this._subscribeToDocumentChanges();
this.updateBlameability(!e.isDirty);
}
private _subscribeToDocumentChanges() {
this._unsubscribeToDocumentChanges();
this._documentChangeDisposable = workspace.onDidChangeTextDocument(this._onTextDocumentChanged, this);
}
private _unsubscribeToDocumentChanges() {
this._documentChangeDisposable && this._documentChangeDisposable.dispose();
this._documentChangeDisposable = undefined;
}
private updateBlameability(blameable: boolean, force: boolean = false) {
if (!force && this._isBlameable === blameable) return;
setCommandContext(CommandContext.IsBlameable, blameable);
this._onDidChange.fire({
blameable: blameable,
editor: this._editor
});
}
}