Skip to content

Commit

Permalink
1.7.0 - Closes waderyan#1, waderyan#3, waderyan#6
Browse files Browse the repository at this point in the history
* Feature: Adding setting to ignore whitespace changes (`gitblame.ignoreWhitespace`) (waderyan#1)
* Feature: Adding setting to open commit info in online tool (`gitblame.commitUrl`) (waderyan#6)
* Enhancement: Status bar message no longer clickable when there is no commit associated with the current line
* Enhancement: Adding info about configuration in `README.md`
* Bug: Spawn fewer git processes when opening a file (waderyan#3)
  • Loading branch information
Sertion committed Apr 30, 2017
1 parent 09d5ea4 commit d616b1a
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 56 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
out
node_modules
node_modules
.vscode/*
!.vscode/launch.json
!.vscode/settings.json
!.vscode/tasks.json
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## 1.7.0 (April 30, 2017)

* Feature: Adding setting to ignore whitespace changes (`gitblame.ignoreWhitespace`) [#1](https://github.com/Sertion/vscode-gitblame/issues/1)
* Feature: Adding setting to open commit info in online tool (`gitblame.commitUrl`) [#6](https://github.com/Sertion/vscode-gitblame/issues/6)
* Enhancement: Status bar message no longer clickable when there is no commit associated with the current line
* Enhancement: Adding info about configuration in `README.md`
* Bug: Spawn fewer git processes when opening a file [#3](https://github.com/Sertion/vscode-gitblame/issues/3)

## 1.6.2 (April 29, 2017)

* Updating example animation
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ Open up VS Code.
4. Type `blame`
5. Select "Git Blame" extension and hit enter

# Configuration

- `gitblame.commitUrl` (`string`, default `""`)
- url where you can see the commit by hash
- Available tokens:
- `${hash}` - the commit hash
- _Example:_ `https://github.com/Sertion/vscode-gitblame/commit/${hash}`
- `gitblame.ignoreWhitespace` (`boolean`, default `false`)
- use the git blame `-w` flag

# [Planned Features](https://github.com/Sertion/vscode-gitblame/labels/Planned)

# [Known Issues](https://github.com/waderyan/vscode-gitblame/issues)
37 changes: 29 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "gitblame",
"displayName": "Git Blame",
"description": "See git blame information in the status bar.",
"version": "1.6.2",
"version": "1.7.0",
"publisher": "waderyan",
"engines": {
"vscode": "^1.10.0"
Expand All @@ -19,7 +19,9 @@
"*"
],
"keywords": [
"git", "gitblame", "blame"
"git",
"gitblame",
"blame"
],
"main": "./out/src/extension",
"scripts": {
Expand All @@ -31,12 +33,13 @@
"dependencies": {
"git-blame": "^1.2.0",
"moment": "^2.10.6",
"path": "^0.12.7"
"object-path": "^0.11.4",
"valid-url": "^1.0.9"
},
"devDependencies": {
"typescript": "^2.0.3",
"vscode": "^1.0.0",
"mocha": "^2.3.3",
"mocha": "^2.3.3",
"@types/node": "^6.0.40",
"@types/mocha": "^2.2.32"
},
Expand All @@ -50,9 +53,27 @@
"url": "https://github.com/Sertion/vscode-gitblame"
},
"contributes": {
"commands": [{
"command": "extension.blame",
"title": "Git Blame"
}]
"commands": [
{
"command": "extension.blame",
"title": "Git Blame"
}
],
"configuration": {
"type": "object",
"title": "Git blame configuration",
"properties": {
"gitblame.ignoreWhitespace": {
"type": "boolean",
"default": false,
"description": "Ignore whitespace changes when blaming (-w flag)"
},
"gitblame.commitUrl": {
"type": "string",
"default": "",
"description": "The link to an online tool to view a commit (use ${hash} for the commit hash)"
}
}
}
}
}
16 changes: 8 additions & 8 deletions src/controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {Disposable, window, workspace, TextEditor, TextEditorSelectionChangeEvent, TextDocument} from 'vscode';
import {GitBlame} from './gitblame';
import {TextDecorator} from '../src/textdecorator';
import {TextDecorator} from '../src/textDecorator';
import * as path from 'path';

export class GitBlameController {

private _disposable: Disposable;
private _textDecorator: TextDecorator

constructor(private gitBlame: GitBlame, private gitRoot: string, private view) {
const self = this;
Expand All @@ -20,7 +19,6 @@ export class GitBlameController {
this.onTextEditorMove(window.activeTextEditor);

this._disposable = Disposable.from(...disposables);
this._textDecorator = new TextDecorator();
}

onTextEditorMove(editor: TextEditor) : void {
Expand All @@ -30,10 +28,11 @@ export class GitBlameController {

const doc = editor.document;

if (!doc) return;
if (doc.isUntitled) return; // Document hasn't been saved and is not in git.
// Document hasn't been saved and is not in git.
if (!doc || doc.isUntitled) return;

const lineNumber = editor.selection.active.line + 1; // line is zero based
// line is zero based
const lineNumber = editor.selection.active.line + 1;
const file = path.relative(this.gitRoot, editor.document.fileName);

this.gitBlame.getBlameInfo(file).then((info) => {
Expand All @@ -58,16 +57,17 @@ export class GitBlameController {
}

clear() {
this.view.refresh('');
this.view.refresh('', false);
}

show(blameInfo: Object, lineNumber: number) : void {

if (lineNumber in blameInfo['lines']) {
const hash = blameInfo['lines'][lineNumber]['hash'];
const commitInfo = blameInfo['commits'][hash];
const clickable = hash !== '0000000000000000000000000000000000000000';

this.view.refresh(this._textDecorator.toTextView(commitInfo));
this.view.refresh(TextDecorator.toTextView(commitInfo), clickable);
}
else {
// No line info.
Expand Down
48 changes: 40 additions & 8 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {GitBlame} from './gitblame';
import {StatusBarView} from './view';
import {GitBlameController} from './controller';
import {TextDecorator} from './textDecorator';
import {window, ExtensionContext, Disposable, StatusBarAlignment,
workspace, TextEditor, TextEditorSelectionChangeEvent, commands} from 'vscode';
workspace, TextEditor, TextEditorSelectionChangeEvent,
commands, Uri} from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

const gitBlameShell = require('git-blame');
import * as gitBlameShell from 'git-blame';
import {isWebUri} from 'valid-url';

export function activate(context: ExtensionContext) {

Expand Down Expand Up @@ -50,6 +52,9 @@ function lookupRepo(context: ExtensionContext, repoDir: string) {

function showMessage(context: ExtensionContext, repoDir: string) {
const repoPath = path.join(repoDir, '.git');
const viewOnlineTitle = 'View';
const config = workspace.getConfiguration('gitblame');
const commitUrl = <string>config.get('commitUrl');

fs.access(repoPath, (err) => {
if (err) {
Expand All @@ -75,13 +80,40 @@ function showMessage(context: ExtensionContext, repoDir: string) {

gitBlame.getBlameInfo(file).then((info) => {

if (lineNumber in info['lines']) {

const hash = info['lines'][lineNumber]['hash'];
const commitInfo = info['commits'][hash];
if (!info['lines'].hasOwnProperty(lineNumber)) return info;

const hash = info['lines'][lineNumber]['hash'];
const commitInfo = info['commits'][hash];
let infoMessageArguments = [];
let urlToUse = null;

// Add the message
infoMessageArguments.push(hash + ' ' + commitInfo['summary']);

window.showInformationMessage(hash + ' ' + commitInfo['summary']);
if (commitUrl) {
// If we have a commitUrl we parse it and add it
let parsedUrl = TextDecorator.parseTokens(commitUrl, {
'hash': hash
});

if (isWebUri(parsedUrl)) {
urlToUse = Uri.parse(parsedUrl);
}
else {
window.showErrorMessage('Malformed URL in setting gitblame.commitUrl. Must be a valid web url');
}

if (urlToUse) {
infoMessageArguments.push(viewOnlineTitle);
}
}

window.showInformationMessage.apply(this, infoMessageArguments)
.then((item) => {
if (item === viewOnlineTitle) {
return commands.executeCommand('vscode.open', urlToUse);
}
}).then(() => {}, error => console.log(error));
});
}
});
Expand Down
23 changes: 18 additions & 5 deletions src/gitblame.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import * as path from 'path';
import {workspace, WorkspaceConfiguration} from 'vscode';

export class GitBlame {

private _blamed: Object;
private _workingOn: Object;
private _properties: WorkspaceConfiguration;

constructor(private repoPath: string, private gitBlameProcess) {
this._blamed = {};
this._workingOn = {};
this._properties = workspace.getConfiguration('gitblame');
}

getBlameInfo(fileName: string): Thenable<any> {
Expand All @@ -30,21 +35,26 @@ export class GitBlame {

fileChanged(fileName: string): void {
delete this._blamed[fileName];
delete this._workingOn[fileName];
}

clearCache(): void {
this._blamed = {};
}

blameFile(repo: string, fileName: string): Thenable<Object> {
const self = this;
return new Promise<Object>((resolve, reject) => {
this._workingOn[fileName] = this._workingOn[fileName] || new Promise<Object>((resolve, reject) => {
const workTree = path.resolve(repo, '..');
const blameInfo = {
'lines': {},
'commits': {}
};

self.gitBlameProcess(repo, {
this.gitBlameProcess(repo, {
file: fileName,
workTree: workTree,
rev: false
rev: false,
ignoreWhitespace: this._properties.get('ignoreWhitespace')
}).on('data', (type, data) => {
// outputs in Porcelain format.
if (type === 'line') {
Expand All @@ -56,9 +66,12 @@ export class GitBlame {
}).on('error', (err) => {
reject(err);
}).on('end', () => {
resolve(blameInfo)
resolve(blameInfo);
delete this._workingOn[fileName];
});
});

return this._workingOn[fileName];
}

dispose() {
Expand Down
35 changes: 32 additions & 3 deletions src/textdecorator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as moment from 'moment';
import * as ObjectPath from 'object-path';

export class TextDecorator {

toTextView(commit: Object) : string {
static toTextView(commit: Object) : string {
const dateNow = new Date();
const author = commit['author'];
const dateText = this.toDateText(dateNow, new Date(author['timestamp'] * 1000));
const dateText = TextDecorator.toDateText(dateNow, new Date(author['timestamp'] * 1000));

if (commit['hash'] === '0000000000000000000000000000000000000000') {
return author['name'];
Expand All @@ -15,7 +16,7 @@ export class TextDecorator {
}
}

toDateText(dateNow: Date, dateThen: Date) : string {
static toDateText(dateNow: Date, dateThen: Date) : string {

const momentNow = moment(dateNow);
const momentThen = moment(dateThen);
Expand All @@ -41,4 +42,32 @@ export class TextDecorator {
return months + ' months ago';
}
}

static parseTokens(target: string, tokens: object = {}): string {
const tokenRegex = /\$\{([a-z\.\-]{1,})[,]*(|[a-z\-,]{1,})}/gi;

return target.replace(tokenRegex, (string: string, key: string, value: string): string => {
let currentToken = ObjectPath.get(tokens, key)

if (typeof currentToken === 'string') {
return currentToken;
}
else if (typeof currentToken === 'number') {
return currentToken.toString();
}
else if (typeof currentToken === 'function') {
let values = value.split(',');
let newString = currentToken.call(this, key, values);

if (typeof newString === 'string') {
return newString;
}
else if (typeof newString === 'number') {
return newString.toString();
}
}

return key;
});
}
}
15 changes: 4 additions & 11 deletions src/view.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@

import {StatusBarItem} from 'vscode';
export interface IView {
/**
* Refresh the view.
*/
refresh(text: string): void;
}

export class StatusBarView implements IView {
export class StatusBarView {

private _statusBarItem: StatusBarItem;

constructor(statusBarItem: StatusBarItem) {
this._statusBarItem = statusBarItem;
this._statusBarItem.command = "extension.blame";
}

refresh(text: string) {
refresh(text: string, hasCommand: boolean = true) {
this._statusBarItem.text = '$(git-commit) ' + text;
this._statusBarItem.tooltip = 'git blame';
this._statusBarItem.tooltip = hasCommand ? 'git blame' : 'git blame - No info about current line';
this._statusBarItem.command = hasCommand ? "extension.blame" : undefined;
this._statusBarItem.show();
}
}
Loading

0 comments on commit d616b1a

Please sign in to comment.