From 19c0e4672969e164208984cf7eb17b39ec7ae92a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 7 Sep 2016 15:45:07 -0400 Subject: [PATCH] Fixes some issues with uncommited blames Automatically turns off blame only when required now --- README.md | 14 ++++++----- package.json | 13 ++++++---- src/commands.ts | 24 +++++++++++++++--- src/gitBlameController.ts | 58 +++++++++++++++++++++++++++++++++++--------- src/gitCodeActionProvider.ts | 2 ++ src/gitProvider.ts | 11 ++++++--- 6 files changed, 92 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index cfac36b..5d93a01 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,19 @@ None yet. ## Known Issues -- Content in the **Blame explorer** disappears after a bit: [Open vscode issue](https://github.com/Microsoft/vscode/issues/11360) -- Highlighted lines disappear in **Blame explorer** after changing selection and returning to a previous selection: [Open vscode issue](https://github.com/Microsoft/vscode/issues/11360) -- CodeLens aren't updated properly after a file is saved: [Open vscode issue](https://github.com/Microsoft/vscode/issues/11546) -- Visible whitespace causes issue with blame overlay (currently fixed with a hack, but fails randomly): [Open vscode issue](https://github.com/Microsoft/vscode/issues/11485) +- Content in the **Blame explorer** disappears after a bit: [vscode issue](https://github.com/Microsoft/vscode/issues/11360) +- Highlighted lines disappear in **Blame explorer** after changing selection and returning to a previous selection: [vscode issue](https://github.com/Microsoft/vscode/issues/11360) +- CodeLens aren't updated properly after a file is saved: [vscode issue](https://github.com/Microsoft/vscode/issues/11546) +- Visible whitespace causes issue with blame overlay (currently fixed with a hack, but fails randomly): [vscode issue](https://github.com/Microsoft/vscode/issues/11485) ## Release Notes ### 0.0.5 -Fixes issues where filename changes in history would cause diffs to fails -Removes CodeLens from fields and single-line properties to reduce visual noise +- Fixes issues where filename changes in history would cause diffs to fails +- Fixes some issues with uncommited blames +- Removes CodeLens from fields and single-line properties to reduce visual noise +- Automatically turns off blame only when required now ### 0.0.4 diff --git a/package.json b/package.json index 0b0fe2b..333236d 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,16 @@ "Other" ], "keywords": [ - "git", "gitblame", "blame", "codelens" + "git", "blame", "history", "log", "codelens" ], "galleryBanner": { "color": "#0000FF", "theme": "dark" }, "preview": true, + "bugs": { + "url": "https://github.com/eamodio/vscode-gitlens/issues" + }, "repository": { "type": "git", "url": "https://github.com/eamodio/vscode-gitlens.git" @@ -28,22 +31,22 @@ "contributes": { "commands": [{ "command": "gitlens.diffWithPrevious", - "title": "GitLens: Open Diff with Previous Commit", + "title": "Git: Open Diff with Previous Commit", "category": "GitLens" }, { "command": "gitlens.diffWithWorking", - "title": "GitLens: Open Diff with Working Tree", + "title": "Git: Open Diff with Working Tree", "category": "GitLens" }, { "command": "gitlens.showBlame", - "title": "GitLens: Show Git Blame", + "title": "Git: Show Blame", "category": "GitLens" }, { "command": "gitlens.toggleBlame", - "title": "GitLens: Toggle Git Blame", + "title": "Git: Toggle Blame", "category": "GitLens" }], "menus": { diff --git a/src/commands.ts b/src/commands.ts index 549b81e..29e0055 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -36,6 +36,8 @@ abstract class EditorCommand extends Disposable { abstract execute(editor: TextEditor, edit: TextEditorEdit, ...args): any; } +const UncommitedRegex = /^[0]+$/; + export class DiffWithPreviousCommand extends EditorCommand { constructor(private git: GitProvider) { super(Commands.DiffWithPrevious); @@ -45,7 +47,14 @@ export class DiffWithPreviousCommand extends EditorCommand { line = line || editor.selection.active.line; if (!sha) { return this.git.getBlameForLine(uri.fsPath, line) - .then(blame => commands.executeCommand(Commands.DiffWithPrevious, uri, blame.commit.sha, blame.commit.toUri(), blame.commit.previousSha, blame.commit.toPreviousUri(), line)); + .then(blame => { + if (!blame) return; + + if (UncommitedRegex.test(blame.commit.sha)) { + return commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.previousSha, blame.commit.toPreviousUri(), line); + } + return commands.executeCommand(Commands.DiffWithPrevious, uri, blame.commit.sha, blame.commit.toUri(), blame.commit.previousSha, blame.commit.toPreviousUri(), line); + }); } if (!compareWithSha) { @@ -69,7 +78,14 @@ export class DiffWithWorkingCommand extends EditorCommand { line = line || editor.selection.active.line; if (!sha) { return this.git.getBlameForLine(uri.fsPath, line) - .then(blame => commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.sha, blame.commit.toUri(), line)); + .then(blame => { + if (!blame) return; + + if (UncommitedRegex.test(blame.commit.sha)) { + return commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.previousSha, blame.commit.toPreviousUri(), line); + } + return commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.sha, blame.commit.toUri(), line) + }); }; // TODO: Moving doesn't always seem to work -- or more accurately it seems like it moves down that number of lines from the current line @@ -92,7 +108,7 @@ export class ShowBlameCommand extends EditorCommand { const activeLine = editor.selection.active.line; return this.git.getBlameForLine(editor.document.fileName, activeLine) - .then(blame => this.blameController.showBlame(editor, blame.commit.sha)); + .then(blame => this.blameController.showBlame(editor, blame && blame.commit.sha)); } } @@ -132,6 +148,6 @@ export class ToggleBlameCommand extends EditorCommand { const activeLine = editor.selection.active.line; return this.git.getBlameForLine(editor.document.fileName, activeLine) - .then(blame => this.blameController.toggleBlame(editor, blame.commit.sha)); + .then(blame => this.blameController.toggleBlame(editor, blame && blame.commit.sha)); } } \ No newline at end of file diff --git a/src/gitBlameController.ts b/src/gitBlameController.ts index 8e6f1dc..bc1a22d 100644 --- a/src/gitBlameController.ts +++ b/src/gitBlameController.ts @@ -1,5 +1,5 @@ 'use strict' -import {commands, DecorationOptions, Diagnostic, DiagnosticCollection, DiagnosticSeverity, Disposable, ExtensionContext, languages, OverviewRulerLane, Position, Range, TextEditor, TextEditorDecorationType, Uri, window, workspace} from 'vscode'; +import {commands, DecorationInstanceRenderOptions, DecorationOptions, Diagnostic, DiagnosticCollection, DiagnosticSeverity, Disposable, ExtensionContext, languages, OverviewRulerLane, Position, Range, TextEditor, TextEditorDecorationType, Uri, window, workspace} from 'vscode'; import {BuiltInCommands, Commands, DocumentSchemes} from './constants'; import GitProvider, {IGitBlame} from './gitProvider'; import GitCodeActionsProvider from './gitCodeActionProvider'; @@ -8,7 +8,6 @@ import * as moment from 'moment'; const blameDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({ before: { - color: '#5a5a5a', margin: '0 1.75em 0 0', width: '5em' }, @@ -46,10 +45,15 @@ export default class GitBlameController extends Disposable { const subscriptions: Disposable[] = []; - subscriptions.push(window.onDidChangeActiveTextEditor(e => { - if (!this._controller || this._controller.editor === e) return; + // subscriptions.push(window.onDidChangeActiveTextEditor(e => { + // if (!e || !this._controller || this._controller.editor === e) return; + // this.clear(); + // })); + + workspace.onDidCloseTextDocument(d => { + if (!this._controller || this._controller.uri.fsPath !== d.uri.fsPath) return; this.clear(); - })); + }) this._disposable = Disposable.from(...subscriptions); } @@ -64,7 +68,7 @@ export default class GitBlameController extends Disposable { this._controller = null; } - showBlame(editor: TextEditor, sha: string) { + showBlame(editor: TextEditor, sha?: string) { if (!editor) { this.clear(); return; @@ -76,7 +80,7 @@ export default class GitBlameController extends Disposable { } } - toggleBlame(editor: TextEditor, sha: string) { + toggleBlame(editor: TextEditor, sha?: string) { if (!editor || this._controller) { this.clear(); return; @@ -87,6 +91,7 @@ export default class GitBlameController extends Disposable { } class GitBlameEditorController extends Disposable { + public uri: Uri; private _disposable: Disposable; private _blame: Promise; private _diagnostics: DiagnosticCollection; @@ -95,7 +100,8 @@ class GitBlameEditorController extends Disposable { constructor(private context: ExtensionContext, private git: GitProvider, public editor: TextEditor) { super(() => this.dispose()); - const fileName = this.editor.document.uri.fsPath; + this.uri = this.editor.document.uri; + const fileName = this.uri.fsPath; this._blame = this.git.getBlameForFile(fileName); const subscriptions: Disposable[] = []; @@ -112,6 +118,8 @@ class GitBlameEditorController extends Disposable { this.git.getBlameForLine(e.textEditor.document.fileName, activeLine) .then(blame => { + if (!blame) return; + // Add the bogus diagnostics to provide code actions for this sha this._diagnostics.set(editor.document.uri, [this._getDiagnostic(editor, activeLine, blame.commit.sha)]); @@ -124,6 +132,7 @@ class GitBlameEditorController extends Disposable { dispose() { if (this.editor) { + // HACK: This only works when switching to another editor - diffs handle whitespace toggle differently if (this._toggleWhitespace) { commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace); } @@ -142,7 +151,7 @@ class GitBlameEditorController extends Disposable { return diag; } - applyBlame(sha: string) { + applyBlame(sha?: string) { return this._blame.then(blame => { if (!blame.lines.length) return; @@ -152,12 +161,39 @@ class GitBlameEditorController extends Disposable { commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace); } + let lastSha; const blameDecorationOptions: DecorationOptions[] = blame.lines.map(l => { + let color = '#6b6b6b'; + const c = blame.commits.get(l.sha); - return { + if (c.previousSha) { + color = '#999999'; + } + + let gutter = ''; + if (lastSha !== l.sha || true) { // TODO: Add a config option + gutter = l.sha.substring(0, 8); + if (gutter === '00000000') { + if (c.previousSha) { + const pc = blame.commits.get(c.previousSha); + if (pc && pc.lines.find(_ => _.line === l.line)) { + gutter = c.previousSha.substring(0, 8); + color = 'rgba(0, 188, 242, 0.6)'; + } + else { + color = 'rgba(127, 186, 0, 0.6)'; + } + } else { + color = 'rgba(127, 186, 0, 0.6)'; + } + } + } + lastSha = l.sha; + + return { range: this.editor.document.validateRange(new Range(l.line, 0, l.line, 0)), hoverMessage: `${c.message}\n${c.author}, ${moment(c.date).format('MMMM Do, YYYY hh:MM a')}`, - renderOptions: { before: { contentText: `${l.sha.substring(0, 8)}`, } } + renderOptions: { before: { color: color, contentText: gutter } } }; }); diff --git a/src/gitCodeActionProvider.ts b/src/gitCodeActionProvider.ts index cff92fe..b3f89b5 100644 --- a/src/gitCodeActionProvider.ts +++ b/src/gitCodeActionProvider.ts @@ -17,6 +17,8 @@ export default class GitCodeActionProvider implements CodeActionProvider { return this.git.getBlameForLine(document.fileName, range.start.line) .then(blame => { const actions: Command[] = []; + if (!blame) return actions; + if (blame.commit.sha) { actions.push({ title: `GitLens: Diff ${blame.commit.sha} with working tree`, diff --git a/src/gitProvider.ts b/src/gitProvider.ts index 5570f1a..48caeda 100644 --- a/src/gitProvider.ts +++ b/src/gitProvider.ts @@ -150,6 +150,8 @@ export default class GitProvider extends Disposable { getBlameForLine(fileName: string, line: number): Promise { return this.getBlameForFile(fileName).then(blame => { const blameLine = blame.lines[line]; + if (!blameLine) return undefined; + const commit = blame.commits.get(blameLine.sha); return { author: Object.assign({}, blame.authors.get(commit.author), { lineCount: commit.lines.length }), @@ -176,7 +178,7 @@ export default class GitProvider extends Disposable { blame.commits.forEach(c => { if (!shas.has(c.sha)) return; - const commit: IGitCommit = Object.assign({}, c, { lines: c.lines.filter(l => l.line >= range.start.line && l.line <= range.end.line) }); + const commit: IGitCommit = new GitCommit(this.repoPath, c.sha, c.fileName, c.author, c.date, c.message, c.lines.filter(l => l.line >= range.start.line && l.line <= range.end.line)); commits.set(c.sha, commit); let author = authors.get(commit.author); @@ -208,7 +210,8 @@ export default class GitProvider extends Disposable { getBlameForShaRange(fileName: string, sha: string, range: Range): Promise { return this.getBlameForFile(fileName).then(blame => { const lines = blame.lines.slice(range.start.line, range.end.line + 1).filter(l => l.sha === sha); - const commit = Object.assign({}, blame.commits.get(sha), { lines: lines }); + let commit = blame.commits.get(sha); + commit = new GitCommit(this.repoPath, commit.sha, commit.fileName, commit.author, commit.date, commit.message, lines); return { author: Object.assign({}, blame.authors.get(commit.author), { lineCount: commit.lines.length }), commit: commit, @@ -345,8 +348,8 @@ class GitCommit implements IGitCommit { previousSha?: string; previousFileName?: string; - constructor(private repoPath: string, public sha: string, public fileName: string, public author: string, public date: Date, public message: string) { - this.lines = []; + constructor(private repoPath: string, public sha: string, public fileName: string, public author: string, public date: Date, public message: string, lines?: IGitCommitLine[]) { + this.lines = lines || []; } toPreviousUri(): Uri {