Browse Source

Fixes #59 - Updates command context to opened file state

Removes insiders restriction from Open in Remote commands
main
Eric Amodio 7 years ago
parent
commit
7cb1b9d0f1
9 changed files with 244 additions and 216 deletions
  1. +42
    -42
      package.json
  2. +3
    -4
      src/blameActiveLineController.ts
  3. +3
    -4
      src/blameAnnotationController.ts
  4. +0
    -100
      src/blameabilityTracker.ts
  5. +3
    -1
      src/commands/common.ts
  6. +6
    -59
      src/extension.ts
  7. +9
    -0
      src/git/git.ts
  8. +163
    -0
      src/git/gitContextTracker.ts
  9. +15
    -6
      src/gitService.ts

+ 42
- 42
package.json View File

@ -517,47 +517,47 @@
},
{
"command": "gitlens.diffWithBranch",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffWithNext",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffWithPrevious",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffLineWithPrevious",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.diffWithWorking",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffLineWithWorking",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.showBlame",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.toggleBlame",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.toggleCodeLens",
"when": "editorTextFocus && gitlens:enabled && gitlens:canToggleCodeLens"
"when": "editorTextFocus && gitlens:isTracked && gitlens:canToggleCodeLens"
},
{
"command": "gitlens.showBlameHistory",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.showFileHistory",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.showLastQuickPick",
@ -565,15 +565,15 @@
},
{
"command": "gitlens.showQuickCommitDetails",
"when": "gitlens:enabled && gitlens:isBlameable"
"when": "gitlens:isBlameable"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"when": "gitlens:enabled && gitlens:isBlameable"
"when": "gitlens:isBlameable"
},
{
"command": "gitlens.showQuickFileHistory",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.showQuickBranchHistory",
@ -593,11 +593,11 @@
},
{
"command": "gitlens.copyShaToClipboard",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.copyMessageToClipboard",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.closeUnchangedFiles",
@ -609,11 +609,11 @@
},
{
"command": "gitlens.openCommitInRemote",
"when": "editorTextFocus && gitlens:enabled && gitlens:hasRemotes && gitlens:isBlameable"
"when": "editorTextFocus && gitlens:isBlameable && gitlens:hasRemotes"
},
{
"command": "gitlens.openFileInRemote",
"when": "editorTextFocus && gitlens:enabled && gitlens:hasRemotes"
"when": "editorTextFocus && gitlens:isTracked && gitlens:hasRemotes"
},
{
"command": "gitlens.stashApply",
@ -642,29 +642,29 @@
},
{
"command": "gitlens.openFileInRemote",
"when": "gitlens:enabled && gitlens:hasRemotes",
"when": "gitlens:enabled",
"group": "1_gitlens_1@2"
}
],
"editor/title": [
{
"command": "gitlens.toggleBlame",
"when": "gitlens:enabled && gitlens:isBlameable",
"when": "gitlens:isBlameable",
"group": "navigation@100"
},
{
"command": "gitlens.diffWithPrevious",
"when": "editorTextFocus && gitlens:enabled && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isTracked && config.gitlens.menus.diff.enabled",
"group": "2_gitlens"
},
{
"command": "gitlens.diffWithWorking",
"when": "editorTextFocus && gitlens:enabled && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isTracked && config.gitlens.menus.diff.enabled",
"group": "2_gitlens"
},
{
"command": "gitlens.showQuickFileHistory",
"when": "editorFocus && gitlens:enabled",
"when": "editorFocus && gitlens:isTracked",
"group": "2_gitlens_1"
},
{
@ -696,64 +696,64 @@
},
{
"command": "gitlens.toggleBlame",
"when": "gitlens:enabled && gitlens:isBlameable",
"when": "gitlens:enabled",
"group": "1_gitlens_1@2"
},
{
"command": "gitlens.openFileInRemote",
"when": "gitlens:enabled && gitlens:hasRemotes",
"when": "gitlens:enabled",
"group": "1_gitlens_1@3"
}
],
"editor/context": [
{
"command": "gitlens.diffLineWithPrevious",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isBlameable && config.gitlens.menus.diff.enabled",
"group": "1_gitlens@1"
},
{
"command": "gitlens.diffLineWithWorking",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isBlameable && config.gitlens.menus.diff.enabled",
"group": "1_gitlens@2"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable",
"when": "editorTextFocus && gitlens:isBlameable",
"group": "1_gitlens@3"
},
{
"command": "gitlens.diffWithPrevious",
"when": "editorTextFocus && gitlens:enabled && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isTracked && config.gitlens.menus.diff.enabled",
"group": "1_gitlens_1@1"
},
{
"command": "gitlens.diffWithWorking",
"when": "editorTextFocus && gitlens:enabled && config.gitlens.menus.diff.enabled",
"when": "editorTextFocus && gitlens:isTracked && config.gitlens.menus.diff.enabled",
"group": "1_gitlens_1@2"
},
{
"command": "gitlens.showQuickFileHistory",
"when": "gitlens:enabled",
"when": "gitlens:isTracked",
"group": "2_gitlens@1"
},
{
"command": "gitlens.toggleBlame",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable",
"when": "editorTextFocus && gitlens:isBlameable",
"group": "2_gitlens@2"
},
{
"command": "gitlens.openFileInRemote",
"when": "editorTextFocus && gitlens:enabled && gitlens:hasRemotes",
"when": "editorTextFocus && gitlens:isTracked && gitlens:hasRemotes",
"group": "2_gitlens@3"
},
{
"command": "gitlens.copyShaToClipboard",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable",
"when": "editorTextFocus && gitlens:isBlameable",
"group": "9_gitlens@1"
},
{
"command": "gitlens.copyMessageToClipboard",
"when": "editorTextFocus && gitlens:enabled && gitlens:isBlameable",
"when": "editorTextFocus && gitlens:isBlameable",
"group": "9_gitlens@2"
}
]
@ -783,13 +783,13 @@
"command": "gitlens.toggleBlame",
"key": "alt+b",
"mac": "alt+b",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.toggleCodeLens",
"key": "alt+shift+b",
"mac": "alt+shift+b",
"when": "editorTextFocus && gitlens:enabled && gitlens:canToggleCodeLens"
"when": "editorTextFocus && gitlens:isTracked && gitlens:canToggleCodeLens"
},
{
"command": "gitlens.showLastQuickPick",
@ -825,31 +825,31 @@
"command": "gitlens.diffWithNext",
"key": "alt+.",
"mac": "alt+.",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffLineWithPrevious",
"key": "shift+alt+,",
"mac": "shift+alt+,",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.diffWithPrevious",
"key": "alt+,",
"mac": "alt+,",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
},
{
"command": "gitlens.diffLineWithWorking",
"key": "alt+w",
"mac": "alt+w",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isBlameable"
},
{
"command": "gitlens.diffWithWorking",
"key": "shift+alt+w",
"mac": "shift+alt+w",
"when": "editorTextFocus && gitlens:enabled"
"when": "editorTextFocus && gitlens:isTracked"
}
]
},

+ 3
- 4
src/blameActiveLineController.ts View File

@ -1,13 +1,12 @@
'use strict';
import { Functions, Objects } from './system';
import { DecorationOptions, DecorationInstanceRenderOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
import { BlameabilityChangeEvent, BlameabilityTracker } from './blameabilityTracker';
import { BlameAnnotationController } from './blameAnnotationController';
import { BlameAnnotationFormat, BlameAnnotationFormatter } from './blameAnnotationFormatter';
import { TextEditorComparer } from './comparers';
import { IBlameConfig, IConfig, StatusBarCommand } from './configuration';
import { DocumentSchemes } from './constants';
import { GitCommit, GitService, GitUri, IGitBlame, IGitCommitLine } from './gitService';
import { BlameabilityChangeEvent, GitCommit, GitContextTracker, GitService, GitUri, IGitBlame, IGitCommitLine } from './gitService';
import * as moment from 'moment';
const activeLineDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
@ -30,7 +29,7 @@ export class BlameActiveLineController extends Disposable {
private _uri: GitUri;
private _useCaching: boolean;
constructor(context: ExtensionContext, private git: GitService, private blameabilityTracker: BlameabilityTracker, private annotationController: BlameAnnotationController) {
constructor(context: ExtensionContext, private git: GitService, private gitContextTracker: GitContextTracker, private annotationController: BlameAnnotationController) {
super(() => this.dispose());
this._updateBlameDebounced = Functions.debounce(this._updateBlame, 50);
@ -95,7 +94,7 @@ export class BlameActiveLineController extends Disposable {
subscriptions.push(window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this));
subscriptions.push(window.onDidChangeTextEditorSelection(this._onTextEditorSelectionChanged, this));
subscriptions.push(this.blameabilityTracker.onDidChange(this._onBlameabilityChanged, this));
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
this._activeEditorLineDisposable = Disposable.from(...subscriptions);
}

+ 3
- 4
src/blameAnnotationController.ts View File

@ -1,11 +1,10 @@
'use strict';
import { Functions } from './system';
import { DecorationRenderOptions, Disposable, Event, EventEmitter, ExtensionContext, OverviewRulerLane, TextDocument, TextEditor, TextEditorDecorationType, TextEditorViewColumnChangeEvent, window, workspace } from 'vscode';
import { BlameabilityChangeEvent, BlameabilityTracker } from './blameabilityTracker';
import { BlameAnnotationProvider } from './blameAnnotationProvider';
import { TextDocumentComparer, TextEditorComparer } from './comparers';
import { IBlameConfig } from './configuration';
import { GitService, GitUri } from './gitService';
import { BlameabilityChangeEvent, GitService, GitUri, GitContextTracker } from './gitService';
import { Logger } from './logger';
import { WhitespaceController } from './whitespaceController';
@ -34,7 +33,7 @@ export class BlameAnnotationController extends Disposable {
private _disposable: Disposable;
private _whitespaceController: WhitespaceController | undefined;
constructor(private context: ExtensionContext, private git: GitService, private blameabilityTracker: BlameabilityTracker) {
constructor(private context: ExtensionContext, private git: GitService, private gitContextTracker: GitContextTracker) {
super(() => this.dispose());
this._onConfigurationChanged();
@ -177,7 +176,7 @@ export class BlameAnnotationController extends Disposable {
subscriptions.push(window.onDidChangeVisibleTextEditors(Functions.debounce(this._onVisibleTextEditorsChanged, 100), this));
subscriptions.push(window.onDidChangeTextEditorViewColumn(this._onTextEditorViewColumnChanged, this));
subscriptions.push(workspace.onDidCloseTextDocument(this._onTextDocumentClosed, this));
subscriptions.push(this.blameabilityTracker.onDidChange(this._onBlameabilityChanged, this));
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
this._blameAnnotationsDisposable = Disposable.from(...subscriptions);
}

+ 0
- 100
src/blameabilityTracker.ts View File

@ -1,100 +0,0 @@
'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
});
}
}

+ 3
- 1
src/commands/common.ts View File

@ -46,12 +46,14 @@ export const Commands = {
ToggleCodeLens: 'gitlens.toggleCodeLens' as Commands
};
export type CommandContext = 'gitlens:canToggleCodeLens' | 'gitlens:enabled' | 'gitlens:hasRemotes' | 'gitlens:isBlameable' | 'gitlens:key';
export type CommandContext = 'gitlens:canToggleCodeLens' | 'gitlens:enabled' | 'gitlens:hasRemotes' | 'gitlens:isBlameable' | 'gitlens:isRepository' | 'gitlens:isTracked' | 'gitlens:key';
export const CommandContext = {
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
Enabled: 'gitlens:enabled' as CommandContext,
HasRemotes: 'gitlens:hasRemotes' as CommandContext,
IsBlameable: 'gitlens:isBlameable' as CommandContext,
IsRepository: 'gitlens:isRepository' as CommandContext,
IsTracked: 'gitlens:isTracked' as CommandContext,
Key: 'gitlens:key' as CommandContext
};

+ 6
- 59
src/extension.ts View File

@ -1,7 +1,6 @@
'use strict';
import { Objects } from './system';
import { commands, Disposable, ExtensionContext, extensions, languages, TextEditor, Uri, window, workspace } from 'vscode';
import { BlameabilityTracker } from './blameabilityTracker';
import { commands, ExtensionContext, extensions, languages, Uri, window, workspace } from 'vscode';
import { BlameActiveLineController } from './blameActiveLineController';
import { BlameAnnotationController } from './blameAnnotationController';
import { configureCssCharacters } from './blameAnnotationFormatter';
@ -20,7 +19,7 @@ import { Keyboard } from './commands';
import { IConfig } from './configuration';
import { ApplicationInsightsKey, BuiltInCommands, ExtensionId, WorkspaceState } from './constants';
import { GitContentProvider } from './gitContentProvider';
import { Git, GitService } from './gitService';
import { Git, GitContextTracker, GitService } from './gitService';
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
import { Logger } from './logger';
import { Telemetry } from './telemetry';
@ -69,19 +68,17 @@ export async function activate(context: ExtensionContext) {
const git = new GitService(context, repoPath);
context.subscriptions.push(git);
setCommandsContext(context, git);
const blameabilityTracker = new BlameabilityTracker(git);
context.subscriptions.push(blameabilityTracker);
const gitContextTracker = new GitContextTracker(git);
context.subscriptions.push(gitContextTracker);
context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider(context, git)));
context.subscriptions.push(languages.registerCodeLensProvider(GitRevisionCodeLensProvider.selector, new GitRevisionCodeLensProvider(context, git)));
const annotationController = new BlameAnnotationController(context, git, blameabilityTracker);
const annotationController = new BlameAnnotationController(context, git, gitContextTracker);
context.subscriptions.push(annotationController);
const activeLineController = new BlameActiveLineController(context, git, blameabilityTracker, annotationController);
const activeLineController = new BlameActiveLineController(context, git, gitContextTracker, annotationController);
context.subscriptions.push(activeLineController);
context.subscriptions.push(new Keyboard());
@ -155,54 +152,4 @@ async function notifyOnUnsupportedGitVersion(context: ExtensionContext, version:
context.globalState.update(WorkspaceState.SuppressGitVersionWarning, true);
}
}
}
let savedGitEnabled: boolean;
let savedInsiders: boolean;
let insidersDisposable: Disposable;
async function setCommandsContext(context: ExtensionContext, git: GitService): Promise<void> {
onCommandsContextConfigurationChanged(git);
context.subscriptions.push(workspace.onDidChangeConfiguration(() => onCommandsContextConfigurationChanged(git), this));
}
async function onCommandsContextConfigurationChanged(git: GitService) {
const gitEnabled = workspace.getConfiguration('git').get<boolean>('enabled');
if (gitEnabled !== savedGitEnabled) {
savedGitEnabled = gitEnabled;
setCommandContext(CommandContext.Enabled, gitEnabled);
}
const insiders = workspace.getConfiguration('gitlens').get<boolean>('insiders');
if (insiders !== savedInsiders) {
savedInsiders = insiders;
insidersDisposable && insidersDisposable.dispose();
if (insiders) {
insidersDisposable = window.onDidChangeActiveTextEditor(e => onActiveTextEditorChanged(e, git));
onActiveTextEditorChanged(window.activeTextEditor, git);
}
else {
insidersDisposable = undefined;
setCommandContext(CommandContext.HasRemotes, false);
}
}
}
async function onActiveTextEditorChanged(editor: TextEditor, git: GitService) {
try {
let hasRemotes = false;
if (editor) {
const repoPath = await git.getRepoPathFromUri(editor.document.uri);
if (repoPath) {
const remotes = await git.getRemotes(repoPath);
hasRemotes = remotes.length !== 0;
}
}
setCommandContext(CommandContext.HasRemotes, hasRemotes);
}
catch (ex) {
Logger.error(ex, 'Extension.onActiveTextEditorChanged');
}
}

+ 9
- 0
src/git/git.ts View File

@ -235,6 +235,15 @@ export class Git {
return gitCommand(root, ...params);
}
static async ls_files(repoPath: string, fileName: string): Promise<string> {
try {
return await gitCommand(repoPath, 'ls-files', fileName);
}
catch (ex) {
return '';
}
}
static remote(repoPath: string): Promise<string> {
return gitCommand(repoPath, 'remote', '-v');
}

+ 163
- 0
src/git/gitContextTracker.ts View File

@ -0,0 +1,163 @@
'use strict';
import { Disposable, Event, EventEmitter, TextDocument, TextDocumentChangeEvent, TextEditor, window, workspace } from 'vscode';
import { CommandContext, setCommandContext } from '../commands';
import { TextDocumentComparer } from '../comparers';
import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
export interface BlameabilityChangeEvent {
blameable: boolean;
editor: TextEditor;
}
export class GitContextTracker extends Disposable {
private _onDidBlameabilityChange = new EventEmitter<BlameabilityChangeEvent>();
get onDidBlameabilityChange(): Event<BlameabilityChangeEvent> {
return this._onDidBlameabilityChange.event;
}
private _disposable: Disposable;
private _documentChangeDisposable: Disposable;
private _editor: TextEditor;
private _gitEnabled: boolean;
private _isBlameable: boolean;
constructor(private git: GitService) {
super(() => this.dispose());
const subscriptions: Disposable[] = [];
subscriptions.push(window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this));
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
subscriptions.push(workspace.onDidSaveTextDocument(this._onTextDocumentSaved, this));
subscriptions.push(this.git.onDidBlameFail(this._onBlameFailed, this));
this._disposable = Disposable.from(...subscriptions);
setCommandContext(CommandContext.IsRepository, !!this.git.repoPath);
this._onConfigurationChanged();
this._onActiveTextEditorChanged(window.activeTextEditor);
}
dispose() {
this._disposable && this._disposable.dispose();
this._documentChangeDisposable && this._documentChangeDisposable.dispose();
}
_onConfigurationChanged() {
const gitEnabled = workspace.getConfiguration('git').get<boolean>('enabled');
if (this._gitEnabled !== gitEnabled) {
this._gitEnabled = gitEnabled;
setCommandContext(CommandContext.Enabled, gitEnabled);
this._onActiveTextEditorChanged(window.activeTextEditor);
}
}
private _onActiveTextEditorChanged(editor: TextEditor) {
this._editor = editor;
this._updateContext(this._gitEnabled && editor);
this._subscribeToDocumentChanges();
}
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 async _updateContext(editor: TextEditor) {
try {
const gitUri = editor && await GitUri.fromUri(editor.document.uri, this.git);
await Promise.all([
this._updateEditorContext(gitUri, editor),
this._updateContextHasRemotes(gitUri)
]);
}
catch (ex) {
Logger.error(ex, 'GitEditorTracker._updateContext');
}
}
private async _updateContextHasRemotes(uri: GitUri | undefined) {
try {
let hasRemotes = false;
if (uri) {
const repoPath = uri.repoPath || this.git.repoPath;
if (repoPath) {
const remotes = await this.git.getRemotes(repoPath);
hasRemotes = remotes.length !== 0;
}
}
setCommandContext(CommandContext.HasRemotes, hasRemotes);
}
catch (ex) {
Logger.error(ex, 'GitEditorTracker._updateContextHasRemotes');
}
}
private async _updateEditorContext(uri: GitUri | undefined, editor: TextEditor | undefined) {
try {
const tracked = uri && await this.git.isTracked(uri);
setCommandContext(CommandContext.IsTracked, tracked);
let blameable = tracked && editor && editor.document && !editor.document.isDirty;
if (blameable) {
blameable = await this.git.getBlameability(uri);
}
this._updateBlameability(blameable, true);
}
catch (ex) {
Logger.error(ex, 'GitEditorTracker._updateEditorContext');
}
}
private _updateBlameability(blameable: boolean, force: boolean = false) {
if (!force && this._isBlameable === blameable) return;
try {
setCommandContext(CommandContext.IsBlameable, blameable);
this._onDidBlameabilityChange.fire({
blameable: blameable,
editor: this._editor
});
}
catch (ex) {
Logger.error(ex, 'GitEditorTracker._updateBlameability');
}
}
}

+ 15
- 6
src/gitService.ts View File

@ -13,9 +13,9 @@ import * as ignore from 'ignore';
import * as moment from 'moment';
import * as path from 'path';
export { getGitStatusIcon } from './git/git';
export { Git, GitUri };
export { GitUri };
export * from './git/git';
export * from './git/gitContextTracker';
class UriCacheEntry {
@ -296,12 +296,14 @@ export class GitService extends Disposable {
}
}
public getBlameability(fileName: string): boolean {
if (!this.UseGitCaching) return true;
public async getBlameability(uri: GitUri): Promise<boolean> {
if (!this.UseGitCaching) return await this.isTracked(uri);
const cacheKey = this.getCacheEntryKey(fileName);
const cacheKey = this.getCacheEntryKey(uri.fsPath);
const entry = this._gitCache.get(cacheKey);
return !(entry && entry.hasErrors);
if (!entry) return await this.isTracked(uri);
return !entry.hasErrors;
}
async getBlameForFile(uri: GitUri): Promise<IGitBlame | undefined> {
@ -752,6 +754,13 @@ export class GitService extends Disposable {
return !!status;
}
async isTracked(uri: GitUri): Promise<boolean> {
Logger.log(`isFileUncommitted('${uri.repoPath}', '${uri.fsPath}')`);
const result = await Git.ls_files(uri.repoPath, uri.fsPath);
return !!result;
}
openDirectoryDiff(repoPath: string, sha1: string, sha2?: string) {
Logger.log(`openDirectoryDiff('${repoPath}', ${sha1}, ${sha2})`);

Loading…
Cancel
Save