Skip to content

Commit 1ec0a29

Browse files
committed
Adds full commit message to blame annotations
Switches to use HoverProvider for hovers in file blames
1 parent f601945 commit 1ec0a29

11 files changed

+139
-210
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
66

77
## [5.0.1] - 2017-09-14
88
### Added
9-
- Adds an external link icon to the `details` hover annotation to run the `Open Commit in Remote` command (`gitlens.openCommitInRemote`)
9+
- Adds an external link icon to the `details` hover annotations to run the `Open Commit in Remote` command (`gitlens.openCommitInRemote`)
10+
- Adds full (multi-line) commit message to the `details` hover annotations
1011

1112
### Changed
1213
- Optimizes performance of the providing blame annotations, especially for large files (saw a ~61% improvement on some files)
1314
- Optimizes date handling (parsing and formatting) for better performance and reduced memory consumption
1415

16+
### Removed
17+
- Removes `gitlens.annotations.file.recentChanges.hover.wholeLine` setting as it didn't really make sense
18+
1519
### Fixed
1620

1721
## [5.0.0] - 2017-09-12

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,6 @@ GitLens is highly customizable and provides many configuration settings to allow
332332
|`gitlens.recentChanges.file.lineHighlight.locations`|Specifies where the highlights of the recently changed lines will be shown<br />`gutter` - adds a gutter glyph<br />`line` - adds a full-line highlight background color<br />`overviewRuler` - adds a decoration to the overviewRuler (scroll bar)
333333
|`gitlens.annotations.file.recentChanges.hover.details`|Specifies whether or not to provide a commit details hover annotation
334334
|`gitlens.annotations.file.recentChanges.hover.changes`|Specifies whether or not to provide a changes (diff) hover annotation
335-
|`gitlens.annotations.file.recentChanges.hover.wholeLine`|Specifies whether or not to trigger hover annotations over the whole line
336335

337336
### Code Lens Settings
338337

package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,6 @@
132132
"default": true,
133133
"description": "Specifies whether or not to provide a changes (diff) hover annotation"
134134
},
135-
"gitlens.annotations.file.recentChanges.hover.wholeLine": {
136-
"type": "boolean",
137-
"default": true,
138-
"description": "Specifies whether or not to trigger hover annotations over the whole line"
139-
},
140135
"gitlens.annotations.line.hover.details": {
141136
"type": "boolean",
142137
"default": true,

src/annotations/annotationController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ export class AnnotationController extends Disposable {
222222
}
223223

224224
getProvider(editor: TextEditor | undefined): AnnotationProviderBase | undefined {
225-
if (!editor || !editor.document || !this.git.isEditorBlameable(editor)) return undefined;
225+
if (editor === undefined || editor.document === undefined || !this.git.isEditorBlameable(editor)) return undefined;
226226

227227
return this._annotationProviders.get(editor.viewColumn || -1);
228228
}
@@ -233,7 +233,7 @@ export class AnnotationController extends Disposable {
233233
if (!editor || !editor.document || !this.git.isEditorBlameable(editor)) return false;
234234

235235
const currentProvider = this._annotationProviders.get(editor.viewColumn || -1);
236-
if (currentProvider && TextEditorComparer.equals(currentProvider.editor, editor)) {
236+
if (currentProvider !== undefined && TextEditorComparer.equals(currentProvider.editor, editor)) {
237237
await currentProvider.selection(shaOrLine);
238238
return true;
239239
}

src/annotations/annotations.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,12 @@ export class Annotations {
187187
} as IRenderOptions;
188188
}
189189

190-
static hover(commit: GitCommit, renderOptions: IRenderOptions, heatmap: boolean, dateFormat: string | null, hasRemotes: boolean): DecorationOptions {
191-
return {
192-
hoverMessage: this.getHoverMessage(commit, dateFormat, hasRemotes),
193-
renderOptions: heatmap ? { before: { ...renderOptions.before } } : undefined
190+
static hover(commit: GitCommit, renderOptions: IRenderOptions, now: number): DecorationOptions {
191+
const decoration = {
192+
renderOptions: { before: { ...renderOptions.before } }
194193
} as DecorationOptions;
194+
this.applyHeatmap(decoration, commit.date, now);
195+
return decoration;
195196
}
196197

197198
static hoverRenderOptions(cfgTheme: IThemeConfig, heatmap: IHeatmapConfig): IRenderOptions {

src/annotations/blameAnnotationProvider.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
'use strict';
22
import { Iterables } from '../system';
3-
import { ExtensionContext, Range, TextEditor, TextEditorDecorationType } from 'vscode';
3+
import { CancellationToken, Disposable, ExtensionContext, Hover, HoverProvider, languages, Position, Range, TextDocument, TextEditor, TextEditorDecorationType } from 'vscode';
44
import { AnnotationProviderBase } from './annotationProvider';
5-
import { GitBlame, GitService, GitUri } from '../gitService';
5+
import { Annotations, endOfLineIndex } from './annotations';
6+
import { GitBlame, GitCommit, GitService, GitUri } from '../gitService';
67
import { WhitespaceController } from './whitespaceController';
78

8-
export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase {
9+
export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase implements HoverProvider {
910

1011
protected _blame: Promise<GitBlame | undefined>;
12+
protected _hoverProviderDisposable: Disposable;
1113

1214
constructor(context: ExtensionContext, editor: TextEditor, decoration: TextEditorDecorationType | undefined, highlightDecoration: TextEditorDecorationType | undefined, whitespaceController: WhitespaceController | undefined, protected git: GitService, protected uri: GitUri) {
1315
super(context, editor, decoration, highlightDecoration, whitespaceController);
1416

1517
this._blame = this.git.getBlameForFile(this.uri);
1618
}
1719

20+
async clear() {
21+
this._hoverProviderDisposable && this._hoverProviderDisposable.dispose();
22+
super.clear();
23+
}
24+
1825
async selection(shaOrLine?: string | number, blame?: GitBlame) {
1926
if (!this.highlightDecoration) return;
2027

@@ -56,6 +63,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
5663
const blame = await this._blame;
5764
return blame !== undefined && blame.lines.length !== 0;
5865
}
66+
5967
protected async getBlame(requiresWhitespaceHack: boolean): Promise<GitBlame | undefined> {
6068
let whitespacePromise: Promise<void> | undefined;
6169
// HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- override whitespace (turn off)
@@ -64,18 +72,47 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
6472
}
6573

6674
let blame: GitBlame | undefined;
67-
if (whitespacePromise) {
75+
if (whitespacePromise !== undefined) {
6876
[blame] = await Promise.all([this._blame, whitespacePromise]);
6977
}
7078
else {
7179
blame = await this._blame;
7280
}
7381

74-
if (blame === undefined || !blame.lines.length) {
82+
if (blame === undefined || blame.lines.length === 0) {
7583
this.whitespaceController && await this.whitespaceController.restore();
7684
return undefined;
7785
}
7886

7987
return blame;
8088
}
89+
90+
registerHoverProvider() {
91+
this._hoverProviderDisposable = languages.registerHoverProvider({ pattern: this.uri.fsPath }, this);
92+
}
93+
94+
async provideHover(document: TextDocument, position: Position, token: CancellationToken): Promise<Hover | undefined> {
95+
// Avoid double annotations if we are showing the whole-file hover blame annotations
96+
if (this._config.blame.line.enabled && this.editor.selection.start.line === position.line) return undefined;
97+
98+
const cfg = this._config.annotations.file.gutter;
99+
if (!cfg.hover.wholeLine && position.character !== 0) return undefined;
100+
101+
const blame = await this.getBlame(true);
102+
if (blame === undefined) return undefined;
103+
104+
const line = blame.lines[position.line - this.uri.offset];
105+
106+
const commit = blame.commits.get(line.sha);
107+
if (commit === undefined) return undefined;
108+
109+
// Get the full commit message -- since blame only returns the summary
110+
let logCommit: GitCommit | undefined = undefined;
111+
if (!commit.isUncommitted) {
112+
logCommit = await this.git.getLogCommit(commit.repoPath, commit.uri.fsPath, commit.sha);
113+
}
114+
115+
const message = Annotations.getHoverMessage(logCommit || commit, this._config.defaultDateFormat, this.git.hasRemotes(commit.repoPath));
116+
return new Hover(message, document.validateRange(new Range(position.line, 0, position.line, endOfLineIndex)));
117+
}
81118
}

src/annotations/gutterBlameAnnotationProvider.ts

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Strings } from '../system';
33
import { DecorationOptions, Range } from 'vscode';
44
import { FileAnnotationType } from './annotationController';
5-
import { Annotations, endOfLineIndex } from './annotations';
5+
import { Annotations } from './annotations';
66
import { BlameAnnotationProviderBase } from './blameAnnotationProvider';
77
import { GlyphChars } from '../constants';
88
import { GitBlameCommit, ICommitFormatOptions } from '../gitService';
@@ -35,18 +35,14 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
3535
const now = Date.now();
3636
const offset = this.uri.offset;
3737
const renderOptions = Annotations.gutterRenderOptions(this._config.theme, cfg.heatmap);
38-
const dateFormat = this._config.defaultDateFormat;
3938
const separateLines = this._config.theme.annotations.file.gutter.separateLines;
4039

4140
const decorations: DecorationOptions[] = [];
42-
const decorationsMap: { [sha: string]: DecorationOptions } = Object.create(null);
43-
const document = this.document;
41+
const decorationsMap: { [sha: string]: DecorationOptions | undefined } = Object.create(null);
4442

4543
let commit: GitBlameCommit | undefined;
4644
let compacted = false;
47-
let details: DecorationOptions | undefined;
4845
let gutter: DecorationOptions | undefined;
49-
let hasRemotes: boolean | undefined;
5046
let previousSha: string | undefined;
5147

5248
for (const l of blame.lines) {
@@ -55,63 +51,50 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
5551
if (previousSha === l.sha) {
5652
// Use a shallow copy of the previous decoration options
5753
gutter = { ...gutter } as DecorationOptions;
54+
5855
if (cfg.compact && !compacted) {
5956
// Since we are wiping out the contextText make sure to copy the objects
60-
gutter.renderOptions = { ...gutter.renderOptions };
61-
gutter.renderOptions.before = {
62-
...gutter.renderOptions.before,
63-
...{ contentText: GlyphChars.Space.repeat(Strings.getWidth(gutter.renderOptions!.before!.contentText!)) }
57+
gutter.renderOptions = {
58+
...gutter.renderOptions,
59+
before: {
60+
...gutter.renderOptions!.before,
61+
contentText: GlyphChars.Space.repeat(Strings.getWidth(gutter.renderOptions!.before!.contentText!))
62+
}
6463
};
6564

6665
if (separateLines) {
67-
gutter.renderOptions.dark = { ...gutter.renderOptions.dark };
68-
gutter.renderOptions.dark.before = { ...gutter.renderOptions.dark.before, ...{ textDecoration: 'none' } };
69-
gutter.renderOptions.light = { ...gutter.renderOptions.light };
70-
gutter.renderOptions.light.before = { ...gutter.renderOptions.light.before, ...{ textDecoration: 'none' } };
66+
gutter.renderOptions.dark = {
67+
...gutter.renderOptions.dark,
68+
before: { ...gutter.renderOptions.dark!.before, textDecoration: 'none' }
69+
};
70+
gutter.renderOptions.light = {
71+
...gutter.renderOptions.light,
72+
before: { ...gutter.renderOptions.light!.before, textDecoration: 'none' }
73+
};
7174
}
7275

7376
compacted = true;
7477
}
7578

76-
const endIndex = document.lineAt(line).firstNonWhitespaceCharacterIndex;
77-
gutter.range = new Range(line, 0, line, endIndex);
79+
gutter.range = new Range(line, 0, line, 0);
7880

7981
decorations.push(gutter);
8082

81-
if (details !== undefined) {
82-
details = { ...details } as DecorationOptions;
83-
details.range = cfg.hover.wholeLine
84-
? document.validateRange(new Range(line, 0, line, endOfLineIndex))
85-
: gutter.range;
86-
87-
decorations.push(details);
88-
}
89-
9083
continue;
9184
}
9285

9386
compacted = false;
9487
previousSha = l.sha;
9588

9689
gutter = decorationsMap[l.sha];
97-
9890
if (gutter !== undefined) {
99-
gutter = { ...gutter } as DecorationOptions;
100-
101-
const endIndex = document.lineAt(line).firstNonWhitespaceCharacterIndex;
102-
gutter.range = new Range(line, 0, line, endIndex);
91+
gutter = {
92+
...gutter,
93+
range: new Range(line, 0, line, 0)
94+
} as DecorationOptions;
10395

10496
decorations.push(gutter);
10597

106-
if (details !== undefined) {
107-
details = { ...details } as DecorationOptions;
108-
details.range = cfg.hover.wholeLine
109-
? document.validateRange(new Range(line, 0, line, endOfLineIndex))
110-
: gutter.range;
111-
112-
decorations.push(details);
113-
}
114-
11598
continue;
11699
}
117100

@@ -124,24 +107,10 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
124107
Annotations.applyHeatmap(gutter, commit.date, now);
125108
}
126109

127-
const endIndex = document.lineAt(line).firstNonWhitespaceCharacterIndex;
128-
gutter.range = new Range(line, 0, line, endIndex);
110+
gutter.range = new Range(line, 0, line, 0);
129111

130112
decorations.push(gutter);
131113
decorationsMap[l.sha] = gutter;
132-
133-
if (cfg.hover.details) {
134-
if (hasRemotes === undefined) {
135-
hasRemotes = this.git.hasRemotes(commit.repoPath);
136-
}
137-
138-
details = Annotations.detailsHover(commit, dateFormat, hasRemotes);
139-
details.range = cfg.hover.wholeLine
140-
? document.validateRange(new Range(line, 0, line, endOfLineIndex))
141-
: gutter.range;
142-
143-
decorations.push(details);
144-
}
145114
}
146115

147116
if (decorations.length) {
@@ -151,6 +120,10 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
151120
const duration = process.hrtime(start);
152121
Logger.log(`${(duration[0] * 1000) + Math.floor(duration[1] / 1000000)} ms to compute gutter blame annotations`);
153122

123+
if (cfg.hover.details) {
124+
this.registerHoverProvider();
125+
}
126+
154127
this.selection(shaOrLine, blame);
155128
return true;
156129
}

0 commit comments

Comments
 (0)