From 157928311e1e5831499b711edc327a763c59a49f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 21 Sep 2016 10:54:45 -0400 Subject: [PATCH] Adds more protection for uncommitted lines Adds better uncommitted hover message in blame annotations --- README.md | 11 ++++++++--- package.json | 2 +- src/blameAnnotationController.ts | 33 ++++++++++++++++++++++---------- src/commands.ts | 16 ++++++++-------- src/git/git.ts | 5 +++-- src/git/gitEnrichment.ts | 10 ++++++++++ src/gitBlameContentProvider.ts | 18 +++++++++-------- src/gitContentProvider.ts | 3 ++- src/gitProvider.ts | 2 ++ 9 files changed, 67 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 4b4a4fb..2f24c6b 100644 --- a/README.md +++ b/README.md @@ -56,17 +56,22 @@ Must be using Git and it must be in your path. --- ## Release Notes +### 0.5.3 + + - Adds better uncommitted hover message in blame annotations + - Adds more protection for dealing with uncommitted lines + ### 0.5.2 - Fixes loading issue on Linux - + ### 0.5.1 - Adds blame information in the statusBar - Add new StatusBar settings -- see **Extension Settings** above for details - Renames the `gitlens.codeLens.recentChange.command` & `gitlens.codeLens.authors.command` settings options (to align with command names) - Adds new `gitlens.diffWithPrevious` option to the `gitlens.codeLens.recentChange.command` & `gitlens.codeLens.authors.command` settings - - Fixes Diff with Previous when the selection is uncommited + - Fixes Diff with Previous when the selection is uncommitted - Removes `gitlens.blame.annotation.useCodeActions` setting and behavior ### 0.3.3 @@ -111,7 +116,7 @@ Must be using Git and it must be in your path. ### 0.0.5 - Fixes issues where filename changes in history would cause diffs to fails -- Fixes some issues with uncommited blames +- Fixes some issues with uncommitted blames - Removes CodeLens from fields and single-line properties to reduce visual noise - Automatically turns off blame only when required now diff --git a/package.json b/package.json index 012bf9d..6f479ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gitlens", - "version": "0.5.2", + "version": "0.5.3", "author": { "name": "Eric Amodio", "email": "eamodio@gmail.com" diff --git a/src/blameAnnotationController.ts b/src/blameAnnotationController.ts index c0de3ee..8a762d1 100644 --- a/src/blameAnnotationController.ts +++ b/src/blameAnnotationController.ts @@ -178,11 +178,17 @@ class EditorBlameAnnotationController extends Disposable { return blame.lines.map(l => { let color = l.previousSha ? '#999999' : '#6b6b6b'; let commit = blame.commits.get(l.sha); - let hoverMessage: string | Array = [`_${l.sha}_: ${commit.message}`, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`]; + let hoverMessage: string | Array = [`_${l.sha}_ - ${commit.message}`, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY h:MM a')}`]; - if (l.sha.startsWith('00000000')) { + if (commit.isUncommitted) { color = 'rgba(0, 188, 242, 0.6)'; - hoverMessage = ''; + + let previous = blame.commits.get(commit.previousSha); + if (previous) { + hoverMessage = ['Uncommitted changes', `_${previous.sha}_ - ${previous.message}`, `${previous.author}, ${moment(previous.date).format('MMMM Do, YYYY h:MM a')}`]; + } else { + hoverMessage = ['Uncommitted changes', `_${l.previousSha}_`]; + } } let gutter = ''; @@ -212,7 +218,7 @@ class EditorBlameAnnotationController extends Disposable { return { range: this.editor.document.validateRange(new Range(l.line, 0, l.line, 0)), - hoverMessage: [`_${l.sha}_: ${commit.message}`, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`], + hoverMessage: hoverMessage, renderOptions: { before: { color: color, contentText: gutter, width: '11em' } } }; }); @@ -243,11 +249,17 @@ class EditorBlameAnnotationController extends Disposable { return blame.lines.map(l => { let color = l.previousSha ? '#999999' : '#6b6b6b'; let commit = blame.commits.get(l.sha); - let hoverMessage: string | Array = [commit.message, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`]; + let hoverMessage: string | Array = [`_${l.sha}_ - ${commit.message}`, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY h:MM a')}`]; - if (l.sha.startsWith('00000000')) { + if (commit.isUncommitted) { color = 'rgba(0, 188, 242, 0.6)'; - hoverMessage = ''; + + let previous = blame.commits.get(commit.previousSha); + if (previous) { + hoverMessage = ['Uncommitted changes', `_${previous.sha}_ - ${previous.message}`, `${previous.author}, ${moment(previous.date).format('MMMM Do, YYYY h:MM a')}`]; + } else { + hoverMessage = ['Uncommitted changes', `_${l.previousSha}_`]; + } } const gutter = this._getGutter(commit); @@ -261,10 +273,11 @@ class EditorBlameAnnotationController extends Disposable { private _getAuthor(commit: IGitCommit, max: number = 17, force: boolean = false) { if (!force && !this._config.annotation.author) return ''; - if (commit.author.length > max) { - return `${commit.author.substring(0, max - 1)}\\2026`; + let author = commit.isUncommitted ? 'Uncommitted': commit.author; + if (author.length > max) { + return `${author.substring(0, max - 1)}\\2026`; } - return commit.author; + return author; } private _getDate(commit: IGitCommit, force?: boolean) { diff --git a/src/commands.ts b/src/commands.ts index 1b017ac..cbd810c 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -42,8 +42,8 @@ export class DiffWithPreviousCommand extends EditorCommand { } execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, repoPath?: string, sha?: string, shaUri?: Uri, compareWithSha?: string, compareWithUri?: Uri, line?: number) { - line = line || editor.selection.active.line; - if (!sha) { + line = line || editor.selection.active.line + 1; + if (!sha || GitProvider.isUncommitted(sha)) { if (!(uri instanceof Uri)) { if (!editor.document) return; uri = editor.document.uri; @@ -56,8 +56,8 @@ export class DiffWithPreviousCommand extends EditorCommand { // If the line is uncommitted, find the previous commit const commit = blame.commit; - if (GitProvider.isUncommitted(commit.sha)) { - return this.git.getBlameForLine(commit.previousUri.fsPath, blame.line.originalLine, commit.previousSha, commit.repoPath) + if (commit.isUncommitted) { + return this.git.getBlameForLine(commit.previousUri.fsPath, blame.line.originalLine + 1, commit.previousSha, commit.repoPath) .catch(ex => console.error('[GitLens.DiffWithPreviousCommand]', `getBlameForLine(${blame.line.originalLine}, ${commit.previousSha})`, ex)) .then(prevBlame => { if (!prevBlame) return; @@ -87,8 +87,8 @@ export class DiffWithWorkingCommand extends EditorCommand { } execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, repoPath?: string, sha?: string, shaUri?: Uri, line?: number) { - line = line || editor.selection.active.line; - if (!sha) { + line = line || editor.selection.active.line + 1; + if (!sha || GitProvider.isUncommitted(sha)) { if (!(uri instanceof Uri)) { if (!editor.document) return; uri = editor.document.uri; @@ -101,8 +101,8 @@ export class DiffWithWorkingCommand extends EditorCommand { const commit = blame.commit; // If the line is uncommitted, find the previous commit - if (GitProvider.isUncommitted(commit.sha)) { - return commands.executeCommand(Commands.DiffWithWorking, commit.uri, commit.repoPath, commit.previousSha, commit.previousUri, blame.line.line); + if (commit.isUncommitted) { + return commands.executeCommand(Commands.DiffWithWorking, commit.uri, commit.repoPath, commit.previousSha, commit.previousUri, blame.line.line + 1); } return commands.executeCommand(Commands.DiffWithWorking, commit.uri, commit.repoPath, commit.sha, commit.uri, line) }); diff --git a/src/git/git.ts b/src/git/git.ts index 0a621cb..8d1ba56 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -7,7 +7,7 @@ import {spawnPromise} from 'spawn-rx'; export * from './gitEnrichment'; export * from './enrichers/blameParserEnricher'; -const UncommitedRegex = /^[0]+$/; +const UncommittedRegex = /^[0]+$/; function gitCommand(cwd: string, ...args) { return spawnPromise('git', args, { cwd: cwd }) @@ -99,10 +99,11 @@ export default class Git { const [file, root] = Git.splitPath(Git.normalizePath(fileName), repoPath); sha = sha.replace('^', ''); + if (Git.isUncommitted(sha)) return new Promise((resolve, reject) => reject(new Error(`sha=${sha} is uncommitted`))); return gitCommand(root, 'show', `${sha}:./${file}`); } static isUncommitted(sha: string) { - return UncommitedRegex.test(sha); + return UncommittedRegex.test(sha); } } \ No newline at end of file diff --git a/src/git/gitEnrichment.ts b/src/git/gitEnrichment.ts index 24171f1..7c84037 100644 --- a/src/git/gitEnrichment.ts +++ b/src/git/gitEnrichment.ts @@ -1,5 +1,6 @@ 'use strict' import {Uri} from 'vscode'; +import Git from './git'; import * as path from 'path'; export interface IGitEnricher { @@ -46,6 +47,7 @@ export interface IGitCommit { previousSha?: string; previousFileName?: string; + readonly isUncommitted: boolean; previousUri: Uri; uri: Uri; } @@ -55,6 +57,7 @@ export class GitCommit implements IGitCommit { originalFileName?: string; previousSha?: string; previousFileName?: string; + private _isUncommitted: boolean|undefined; constructor(public repoPath: string, public sha: string, public fileName: string, public author: string, public date: Date, public message: string, lines?: IGitCommitLine[], originalFileName?: string, previousSha?: string, previousFileName?: string) { @@ -64,6 +67,13 @@ export class GitCommit implements IGitCommit { this.previousFileName = previousFileName; } + get isUncommitted(): boolean { + if (this._isUncommitted === undefined) { + this._isUncommitted = Git.isUncommitted(this.sha); + } + return this._isUncommitted; + } + get previousUri(): Uri { return this.previousFileName ? Uri.file(path.join(this.repoPath, this.previousFileName)) : this.uri; } diff --git a/src/gitBlameContentProvider.ts b/src/gitBlameContentProvider.ts index c87aef9..9c9e84d 100644 --- a/src/gitBlameContentProvider.ts +++ b/src/gitBlameContentProvider.ts @@ -51,17 +51,19 @@ export default class GitBlameContentProvider implements TextDocumentContentProvi //const editor = this._findEditor(Uri.file(join(data.repoPath, data.file))); - return this.git.getVersionedFileText(data.originalFileName || data.fileName, data.repoPath, data.sha).then(text => { - this.update(uri); + return this.git.getVersionedFileText(data.originalFileName || data.fileName, data.repoPath, data.sha) + .then(text => { + this.update(uri); - // TODO: This only works on the first load -- not after since it is cached - this._tryAddBlameDecorations(uri, data); + // TODO: This only works on the first load -- not after since it is cached + this._tryAddBlameDecorations(uri, data); - // TODO: This needs to move to selection somehow to show on the main file editor - //this._addBlameDecorations(editor, data); + // TODO: This needs to move to selection somehow to show on the main file editor + //this._addBlameDecorations(editor, data); - return text; - }); + return text; + }) + .catch(ex => console.error('[GitLens.GitBlameContentProvider]', 'getVersionedFileText', ex)); // return this.git.getVersionedFile(data.fileName, data.sha).then(dst => { // let uri = Uri.parse(`file:${dst}`) diff --git a/src/gitContentProvider.ts b/src/gitContentProvider.ts index 89a6e27..bf93ac4 100644 --- a/src/gitContentProvider.ts +++ b/src/gitContentProvider.ts @@ -10,6 +10,7 @@ export default class GitContentProvider implements TextDocumentContentProvider { provideTextDocumentContent(uri: Uri): string | Thenable { const data = GitProvider.fromGitUri(uri); - return this.git.getVersionedFileText(data.originalFileName || data.fileName, data.repoPath, data.sha); + return this.git.getVersionedFileText(data.originalFileName || data.fileName, data.repoPath, data.sha) + .catch(ex => console.error('[GitLens.GitContentProvider]', 'getVersionedFileText', ex)); } } \ No newline at end of file diff --git a/src/gitProvider.ts b/src/gitProvider.ts index 68dffea..2d5b97b 100644 --- a/src/gitProvider.ts +++ b/src/gitProvider.ts @@ -306,6 +306,8 @@ export default class GitProvider extends Disposable { const locations: Array = []; Array.from(blame.commits.values()) .forEach((c, i) => { + if (c.isUncommitted) return; + const uri = GitProvider.toBlameUri(c, i + 1, commitCount, range); c.lines.forEach(l => locations.push(new Location(c.originalFileName ? GitProvider.toBlameUri(c, i + 1, commitCount, range, c.originalFileName)