Reworks the design of hover annotations

Combines activeline annotation settings
This commit is contained in:
Eric Amodio
2017-02-06 14:59:08 -05:00
parent dfacc2bf6e
commit 9edf629c3b
5 changed files with 69 additions and 49 deletions

View File

@@ -77,10 +77,16 @@
"default": false, "default": false,
"description": "Specifies whether the commit message will be shown in the blame annotations. Applies only to the `expanded` & `trailing` annotation styles" "description": "Specifies whether the commit message will be shown in the blame annotations. Applies only to the `expanded` & `trailing` annotation styles"
}, },
"gitlens.blame.annotation.activeLine.enabled": { "gitlens.blame.annotation.activeLine": {
"type": "boolean", "type": "string",
"default": true, "default": "both",
"description": "Specifies whether to show a trailing blame annotation (sha and commit message) of the active line" "enum": [
"off",
"inline",
"hover",
"both"
],
"description": "Specifies whether and how to show blame annotations on the active line. `off` - no annotation. `inline` - adds a trailing annotation to the active line. `hover` - adds hover annotation to the active line. `both` - adds both `inline` and `hover` annotations"
}, },
"gitlens.codeLens.visibility": { "gitlens.codeLens.visibility": {
"type": "string", "type": "string",

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
import { IBlameConfig } from './configuration'; import { IBlameConfig } from './configuration';
import { GitCommit, IGitBlame, IGitCommitLine } from './gitProvider'; import { GitCommit, IGitCommitLine } from './gitProvider';
import * as moment from 'moment'; import * as moment from 'moment';
export const defaultShaLength = 8; export const defaultShaLength = 8;
@@ -50,38 +50,24 @@ export default class BlameAnnotationFormatter {
return message; return message;
} }
static getAnnotationHover(config: IBlameConfig, line: IGitCommitLine, commit: GitCommit, blame?: IGitBlame): string | Array<string> { static getAnnotationHover(config: IBlameConfig, line: IGitCommitLine, commit: GitCommit): string | Array<string> {
const message = commit.message.replace(/\n/g, '\n\n');
if (commit.isUncommitted) { if (commit.isUncommitted) {
let previous = blame && blame.commits.get(commit.previousSha); return `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted changes__ \n\n > ${message}`;
if (previous) {
return [
'Uncommitted changes',
`_${previous.sha}_ - ${previous.message}`,
`${previous.author}, ${moment(previous.date).format('MMMM Do, YYYY h:MMa')}`
];
}
return [
'Uncommitted changes',
`_${line.previousSha}_`
];
} }
return [ return `\`${commit.sha}\` &nbsp; __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format('MMMM Do, YYYY h:MMa')})_ \n\n > ${message}`;
`_${commit.sha}_ - ${commit.message}`,
`${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY h:MMa')}`
];
} }
static getAuthorAndDate(config: IBlameConfig, commit: GitCommit, format?: string/*, truncate: boolean = false*/, force: boolean = false) { static getAuthorAndDate(config: IBlameConfig, commit: GitCommit, format?: string, force: boolean = false) {
if (!force && !config.annotation.author && (!config.annotation.date || config.annotation.date === 'off')) return ''; if (!force && !config.annotation.author && (!config.annotation.date || config.annotation.date === 'off')) return '';
if (!config.annotation.author) { if (!config.annotation.author) {
return this.getDate(config, commit, format); //, truncate); return this.getDate(config, commit, format);
} }
if (!config.annotation.date || config.annotation.date === 'off') { if (!config.annotation.date || config.annotation.date === 'off') {
return this.getAuthor(config, commit); //, truncate ? defaultAuthorLength : 0); return this.getAuthor(config, commit);
} }
return `${this.getAuthor(config, commit)}, ${this.getDate(config, commit, format)}`; return `${this.getAuthor(config, commit)}, ${this.getDate(config, commit, format)}`;

View File

@@ -167,8 +167,6 @@ export class BlameAnnotationProvider extends Disposable {
color = l.previousSha ? '#999999' : '#6b6b6b'; color = l.previousSha ? '#999999' : '#6b6b6b';
} }
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(this._config, l, commit, blame);
let gutter = ''; let gutter = '';
if (lastSha !== l.sha) { if (lastSha !== l.sha) {
count = -1; count = -1;
@@ -192,6 +190,8 @@ export class BlameAnnotationProvider extends Disposable {
} }
} }
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(this._config, l, commit);
// Escape single quotes because for some reason that breaks the ::before or ::after element // Escape single quotes because for some reason that breaks the ::before or ::after element
gutter = gutter.replace(/\'/g, '\\\''); gutter = gutter.replace(/\'/g, '\\\'');
@@ -274,11 +274,10 @@ export class BlameAnnotationProvider extends Disposable {
} }
} }
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(this._config, l, commit, blame);
const format = trailing ? BlameAnnotationFormat.Unconstrained : BlameAnnotationFormat.Constrained; const format = trailing ? BlameAnnotationFormat.Unconstrained : BlameAnnotationFormat.Constrained;
// Escape single quotes because for some reason that breaks the ::before or ::after element // Escape single quotes because for some reason that breaks the ::before or ::after element
const gutter = BlameAnnotationFormatter.getAnnotation(this._config, commit, format).replace(/\'/g, '\\\''); const gutter = BlameAnnotationFormatter.getAnnotation(this._config, commit, format).replace(/\'/g, '\\\'');
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(this._config, l, commit);
let renderOptions: DecorationInstanceRenderOptions; let renderOptions: DecorationInstanceRenderOptions;
if (trailing) { if (trailing) {

View File

@@ -72,7 +72,7 @@ export default class BlameStatusBarController extends Disposable {
if (!Objects.areEquivalent(config.blame.annotation.activeLine, this._config && this._config.blame.annotation.activeLine)) { if (!Objects.areEquivalent(config.blame.annotation.activeLine, this._config && this._config.blame.annotation.activeLine)) {
changed = true; changed = true;
if (!config.blame.annotation.activeLine.enabled && this._editor) { if (config.blame.annotation.activeLine !== 'off' && this._editor) {
this._editor.setDecorations(activeLineDecoration, []); this._editor.setDecorations(activeLineDecoration, []);
} }
} }
@@ -81,7 +81,7 @@ export default class BlameStatusBarController extends Disposable {
if (!changed) return; if (!changed) return;
let trackActiveLine = config.statusBar.enabled || config.blame.annotation.activeLine.enabled; let trackActiveLine = config.statusBar.enabled || config.blame.annotation.activeLine !== 'off';
if (trackActiveLine && !this._activeEditorLineDisposable) { if (trackActiveLine && !this._activeEditorLineDisposable) {
const subscriptions: Disposable[] = []; const subscriptions: Disposable[] = [];
@@ -176,7 +176,7 @@ export default class BlameStatusBarController extends Disposable {
this._statusBarItem && this._statusBarItem.hide(); this._statusBarItem && this._statusBarItem.hide();
} }
show(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) { async show(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
if (this._config.statusBar.enabled) { if (this._config.statusBar.enabled) {
this._statusBarItem.text = `$(git-commit) ${commit.author}, ${moment(commit.date).fromNow()}`; this._statusBarItem.text = `$(git-commit) ${commit.author}, ${moment(commit.date).fromNow()}`;
@@ -204,7 +204,7 @@ export default class BlameStatusBarController extends Disposable {
this._statusBarItem.show(); this._statusBarItem.show();
} }
if (this._config.blame.annotation.activeLine.enabled) { if (this._config.blame.annotation.activeLine !== 'off') {
const offset = this._uri.offset; const offset = this._uri.offset;
const config = { const config = {
@@ -218,20 +218,51 @@ export default class BlameStatusBarController extends Disposable {
// Escape single quotes because for some reason that breaks the ::before or ::after element // Escape single quotes because for some reason that breaks the ::before or ::after element
const annotation = BlameAnnotationFormatter.getAnnotation(config, commit, BlameAnnotationFormat.Unconstrained).replace(/\'/g, '\\\''); const annotation = BlameAnnotationFormatter.getAnnotation(config, commit, BlameAnnotationFormat.Unconstrained).replace(/\'/g, '\\\'');
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(config, blameLine, commit);
const decorationOptions = { // Get the full commit message -- since blame only returns the summary
range: editor.document.validateRange(new Range(blameLine.line + offset, 1000000, blameLine.line + offset, 1000000)), let logCommit: GitCommit;
hoverMessage: hoverMessage, if (!commit.isUncommitted) {
renderOptions: { const log = await this.git.getLogForFile(this._uri.fsPath, commit.sha, this._uri.repoPath, undefined, 1);
after: { logCommit = log && log.commits.get(commit.sha);
color: 'rgba(153, 153, 153, 0.3)', }
contentText: annotation const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(config, blameLine, logCommit || commit);
}
} as DecorationInstanceRenderOptions
} as DecorationOptions;
editor.setDecorations(activeLineDecoration, [decorationOptions]); let decorationOptions: DecorationOptions;
switch (this._config.blame.annotation.activeLine) {
case 'both':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 0, blameLine.line + offset, 1000000)),
hoverMessage: hoverMessage,
renderOptions: {
after: {
color: 'rgba(153, 153, 153, 0.3)',
contentText: annotation
}
} as DecorationInstanceRenderOptions
} as DecorationOptions;
break;
case 'inline':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 1000000, blameLine.line + offset, 1000000)),
renderOptions: {
after: {
color: 'rgba(153, 153, 153, 0.3)',
contentText: annotation
}
} as DecorationInstanceRenderOptions
} as DecorationOptions;
break;
case 'hover':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 0, blameLine.line + offset, 1000000)),
hoverMessage: hoverMessage
} as DecorationOptions;
break;
}
decorationOptions && editor.setDecorations(activeLineDecoration, [decorationOptions]);
} }
} }
} }

View File

@@ -15,9 +15,7 @@ export interface IBlameConfig {
author: boolean; author: boolean;
date: 'off' | 'relative' | 'absolute'; date: 'off' | 'relative' | 'absolute';
message: boolean; message: boolean;
activeLine: { activeLine: 'off' | 'inline' | 'hover' | 'both';
enabled: boolean;
};
}; };
} }