mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-16 18:48:45 -05:00
Adds many new settings
Adds new blame annotation styles (compact & expanded) Cleaned up blame annotations Fixes issue with invalid repoPath on first start
This commit is contained in:
20
README.md
20
README.md
@@ -7,9 +7,10 @@ Provides Git blame and blame history CodeLens for many supported Visual Studio C
|
|||||||
Provides two CodeLens on code blocks:
|
Provides two CodeLens on code blocks:
|
||||||
- **Recent Change** - author and date of the most recent check-in
|
- **Recent Change** - author and date of the most recent check-in
|
||||||
> Clicking on the CodeLens opens a **Blame explorer** with the commits and changed lines in the right pane and the commit (file) contents on the left
|
> Clicking on the CodeLens opens a **Blame explorer** with the commits and changed lines in the right pane and the commit (file) contents on the left
|
||||||
- **Blame** - number of authors of a block and the most prominent author (if there are more than one)
|
- **Authors** - number of authors of a block and the most prominent author (if there are more than one)
|
||||||
> Clicking on the CodeLens toggles Git blame overlay
|
> Clicking on the CodeLens toggles Git blame annotations on/off
|
||||||
|
|
||||||
|
## Screenshot
|
||||||
> 
|
> 
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
@@ -18,7 +19,7 @@ Must be using Git and it must be in your path.
|
|||||||
|
|
||||||
## Extension Settings
|
## Extension Settings
|
||||||
|
|
||||||
None yet.
|
See the Contributions tab above
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
@@ -29,7 +30,20 @@ None yet.
|
|||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
|
### 0.1.0
|
||||||
|
|
||||||
|
- Improved blame annotations, now with sha and author by default
|
||||||
|
- Add new blame annotation styles -- compact and expanded (default)
|
||||||
|
- Adds many new configuration settings; see Contributions tab above
|
||||||
|
|
||||||
|
### 0.0.7
|
||||||
|
|
||||||
|
- Fixes [#4](https://github.com/eamodio/vscode-gitlens/issues/4) - Absolute paths fail on Windows due to backslash (Really!)
|
||||||
|
- Fixes [#5](https://github.com/eamodio/vscode-gitlens/issues/5) - Finding first non-white-space fails sometimes
|
||||||
|
- Adds .gitignore checks to reduce the number of blame calls
|
||||||
|
|
||||||
### 0.0.6
|
### 0.0.6
|
||||||
|
|
||||||
- Fixes [#2](https://github.com/eamodio/vscode-gitlens/issues/2) - [request] Provide some debug info when things fail
|
- Fixes [#2](https://github.com/eamodio/vscode-gitlens/issues/2) - [request] Provide some debug info when things fail
|
||||||
- Fixes [#4](https://github.com/eamodio/vscode-gitlens/issues/4) - Absolute paths fail on Windows due to backslash
|
- Fixes [#4](https://github.com/eamodio/vscode-gitlens/issues/4) - Absolute paths fail on Windows due to backslash
|
||||||
- Attempts to scroll to the correct position when opening a diff
|
- Attempts to scroll to the correct position when opening a diff
|
||||||
|
|||||||
69
package.json
69
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitlens",
|
"name": "gitlens",
|
||||||
"version": "0.0.7",
|
"version": "0.1.0",
|
||||||
"author": "Eric Amodio",
|
"author": "Eric Amodio",
|
||||||
"publisher": "eamodio",
|
"publisher": "eamodio",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"color": "#0000FF",
|
"color": "#0000FF",
|
||||||
"theme": "dark"
|
"theme": "dark"
|
||||||
},
|
},
|
||||||
"preview": true,
|
"preview": false,
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/eamodio/vscode-gitlens/issues"
|
"url": "https://github.com/eamodio/vscode-gitlens/issues"
|
||||||
},
|
},
|
||||||
@@ -29,6 +29,71 @@
|
|||||||
},
|
},
|
||||||
"main": "./out/src/extension",
|
"main": "./out/src/extension",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
|
"configuration": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "GitLens configuration",
|
||||||
|
"properties": {
|
||||||
|
"gitlens.blame.annotation.style": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "expanded",
|
||||||
|
"enum": [
|
||||||
|
"compact",
|
||||||
|
"expanded"
|
||||||
|
],
|
||||||
|
"description": "Specifies the style of the blame annotations. Compact - groups annotations to limit the repetition and also adds author and date when possible. Expanded - shows an annotation on every line"
|
||||||
|
},
|
||||||
|
"gitlens.blame.annotation.sha": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether the commit sha will be shown in the blame annotations. Applies only to the Expanded annotation style"
|
||||||
|
},
|
||||||
|
"gitlens.blame.annotation.author": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether the committer will be shown in the blame annotations. Applies only to the Expanded annotation style"
|
||||||
|
},
|
||||||
|
"gitlens.blame.annotation.date": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether the commit date will be shown in the blame annotations. Applies only to the Expanded annotation style"
|
||||||
|
},
|
||||||
|
"gitlens.blame.annotation.useCodeActions": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether code actions (Diff with Working, Diff with Previous) will be provided for the selected line, when annotating. Not required as context menu options are always provided"
|
||||||
|
},
|
||||||
|
"gitlens.codeLens.recentChange.enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether the recent change CodeLens is shown"
|
||||||
|
},
|
||||||
|
"gitlens.codeLens.recentChange.command": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "blame.explorer",
|
||||||
|
"enum": [
|
||||||
|
"blame.annotate",
|
||||||
|
"blame.explorer",
|
||||||
|
"git.history"
|
||||||
|
],
|
||||||
|
"description": "Specifies the command executed when the recent change CodeLens is clicked. Annotate - toggles blame annotations. Explorer - opens the blame explorer. History - opens a file history picker, which requires the Git History (git log) extension"
|
||||||
|
},
|
||||||
|
"gitlens.codeLens.authors.enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether the authors CodeLens is shown"
|
||||||
|
},
|
||||||
|
"gitlens.codeLens.authors.command": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "blame.annotate",
|
||||||
|
"enum": [
|
||||||
|
"blame.annotate",
|
||||||
|
"blame.explorer",
|
||||||
|
"git.history"
|
||||||
|
],
|
||||||
|
"description": "Specifies the command executed when the authors CodeLens is clicked. Annotate - toggles blame annotations. Explorer - opens the blame explorer. History - opens a file history picker, which requires the Git History (git log) extension"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"commands": [{
|
"commands": [{
|
||||||
"command": "gitlens.diffWithPrevious",
|
"command": "gitlens.diffWithPrevious",
|
||||||
"title": "Git: Open Diff with Previous Commit",
|
"title": "Git: Open Diff with Previous Commit",
|
||||||
|
|||||||
32
src/configuration.ts
Normal file
32
src/configuration.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
export type BlameAnnotationStyle = 'compact' | 'expanded';
|
||||||
|
export const BlameAnnotationStyle = {
|
||||||
|
Compact: 'compact' as BlameAnnotationStyle,
|
||||||
|
Expanded: 'expanded' as BlameAnnotationStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBlameConfig {
|
||||||
|
annotation: {
|
||||||
|
style: BlameAnnotationStyle;
|
||||||
|
sha: boolean;
|
||||||
|
author: boolean;
|
||||||
|
date: boolean;
|
||||||
|
useCodeActions: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CodeLensCommand = 'blame.annotate' | 'blame.explorer' | 'git.history';
|
||||||
|
export const CodeLensCommand = {
|
||||||
|
BlameAnnotate: 'blame.annotate' as CodeLensCommand,
|
||||||
|
BlameExplorer: 'blame.explorer' as CodeLensCommand,
|
||||||
|
GitHistory: 'git.history' as CodeLensCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICodeLensConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
command: CodeLensCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICodeLensesConfig {
|
||||||
|
recentChange: ICodeLensConfig;
|
||||||
|
authors: ICodeLensConfig;
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@ import GitBlameCodeLensProvider from './gitBlameCodeLensProvider';
|
|||||||
import GitBlameContentProvider from './gitBlameContentProvider';
|
import GitBlameContentProvider from './gitBlameContentProvider';
|
||||||
import GitBlameController from './gitBlameController';
|
import GitBlameController from './gitBlameController';
|
||||||
import GitProvider from './gitProvider';
|
import GitProvider from './gitProvider';
|
||||||
|
import Git from './git';
|
||||||
import {DiffWithPreviousCommand, DiffWithWorkingCommand, ShowBlameCommand, ShowBlameHistoryCommand, ToggleBlameCommand} from './commands';
|
import {DiffWithPreviousCommand, DiffWithWorkingCommand, ShowBlameCommand, ShowBlameHistoryCommand, ToggleBlameCommand} from './commands';
|
||||||
|
import {ICodeLensesConfig} from './configuration';
|
||||||
import {WorkspaceState} from './constants';
|
import {WorkspaceState} from './constants';
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
@@ -19,17 +21,20 @@ export function activate(context: ExtensionContext) {
|
|||||||
|
|
||||||
console.log(`GitLens active: ${workspace.rootPath}`);
|
console.log(`GitLens active: ${workspace.rootPath}`);
|
||||||
|
|
||||||
|
Git.repoPath(workspace.rootPath).then(repoPath => {
|
||||||
|
context.workspaceState.update(WorkspaceState.RepoPath, repoPath);
|
||||||
|
context.workspaceState.update(WorkspaceState.HasGitHistoryExtension, extensions.getExtension('donjayamanne.githistory') !== undefined);
|
||||||
|
|
||||||
const git = new GitProvider(context);
|
const git = new GitProvider(context);
|
||||||
context.subscriptions.push(git);
|
context.subscriptions.push(git);
|
||||||
|
|
||||||
git.getRepoPath(workspace.rootPath).then(repoPath => {
|
|
||||||
context.workspaceState.update(WorkspaceState.RepoPath, repoPath);
|
|
||||||
//context.workspaceState.update(WorkspaceState.HasGitHistoryExtension, extensions.getExtension('donjayamanne.githistory') !== undefined);
|
|
||||||
|
|
||||||
context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider(context, git)));
|
context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider(context, git)));
|
||||||
context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitBlameContentProvider.scheme, new GitBlameContentProvider(context, git)));
|
context.subscriptions.push(workspace.registerTextDocumentContentProvider(GitBlameContentProvider.scheme, new GitBlameContentProvider(context, git)));
|
||||||
|
|
||||||
|
const config = workspace.getConfiguration('gitlens').get<ICodeLensesConfig>('codeLens');
|
||||||
|
if (config.recentChange.enabled || config.authors.enabled) {
|
||||||
context.subscriptions.push(languages.registerCodeLensProvider(GitBlameCodeLensProvider.selector, new GitBlameCodeLensProvider(context, git)));
|
context.subscriptions.push(languages.registerCodeLensProvider(GitBlameCodeLensProvider.selector, new GitBlameCodeLensProvider(context, git)));
|
||||||
|
}
|
||||||
|
|
||||||
const blameController = new GitBlameController(context, git);
|
const blameController = new GitBlameController(context, git);
|
||||||
context.subscriptions.push(blameController);
|
context.subscriptions.push(blameController);
|
||||||
|
|||||||
10
src/git.ts
10
src/git.ts
@@ -53,6 +53,16 @@ export default class Git {
|
|||||||
return gitCommand(repoPath, 'blame', '--porcelain', '--root', '--', fileName);
|
return gitCommand(repoPath, 'blame', '--porcelain', '--root', '--', fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static blameLinePorcelain(fileName: string, repoPath: string, sha?: string) {
|
||||||
|
fileName = Git.normalizePath(fileName, repoPath);
|
||||||
|
|
||||||
|
if (sha) {
|
||||||
|
return gitCommand(repoPath, 'blame', '--line-porcelain', '--root', `${sha}^`, '--', fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gitCommand(repoPath, 'blame', '--line-porcelain', '--root', '--', fileName);
|
||||||
|
}
|
||||||
|
|
||||||
static getVersionedFile(fileName: string, repoPath: string, sha: string) {
|
static getVersionedFile(fileName: string, repoPath: string, sha: string) {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
Git.getVersionedFileText(fileName, repoPath, sha).then(data => {
|
Git.getVersionedFileText(fileName, repoPath, sha).then(data => {
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
import {commands, DecorationInstanceRenderOptions, 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 {BuiltInCommands, Commands, DocumentSchemes} from './constants';
|
||||||
import GitProvider, {IGitBlame} from './gitProvider';
|
import {BlameAnnotationStyle, IBlameConfig} from './configuration';
|
||||||
|
import GitProvider, {IGitBlame, IGitCommit} from './gitProvider';
|
||||||
import GitCodeActionsProvider from './gitCodeActionProvider';
|
import GitCodeActionsProvider from './gitCodeActionProvider';
|
||||||
import {DiagnosticCollectionName, DiagnosticSource} from './constants';
|
import {DiagnosticCollectionName, DiagnosticSource} from './constants';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
const blameDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
const blameDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||||
before: {
|
before: {
|
||||||
margin: '0 1.75em 0 0',
|
margin: '0 1.75em 0 0'
|
||||||
width: '5em'
|
}
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let highlightDecoration: TextEditorDecorationType;
|
let highlightDecoration: TextEditorDecorationType;
|
||||||
|
|
||||||
export default class GitBlameController extends Disposable {
|
export default class GitBlameController extends Disposable {
|
||||||
@@ -92,9 +91,11 @@ export default class GitBlameController extends Disposable {
|
|||||||
|
|
||||||
class GitBlameEditorController extends Disposable {
|
class GitBlameEditorController extends Disposable {
|
||||||
public uri: Uri;
|
public uri: Uri;
|
||||||
private _disposable: Disposable;
|
|
||||||
private _blame: Promise<IGitBlame>;
|
private _blame: Promise<IGitBlame>;
|
||||||
|
private _config: IBlameConfig;
|
||||||
private _diagnostics: DiagnosticCollection;
|
private _diagnostics: DiagnosticCollection;
|
||||||
|
private _disposable: Disposable;
|
||||||
private _toggleWhitespace: boolean;
|
private _toggleWhitespace: boolean;
|
||||||
|
|
||||||
constructor(private context: ExtensionContext, private git: GitProvider, public editor: TextEditor) {
|
constructor(private context: ExtensionContext, private git: GitProvider, public editor: TextEditor) {
|
||||||
@@ -104,24 +105,28 @@ class GitBlameEditorController extends Disposable {
|
|||||||
const fileName = this.uri.fsPath;
|
const fileName = this.uri.fsPath;
|
||||||
this._blame = this.git.getBlameForFile(fileName);
|
this._blame = this.git.getBlameForFile(fileName);
|
||||||
|
|
||||||
|
this._config = workspace.getConfiguration('gitlens').get<IBlameConfig>('blame');
|
||||||
|
|
||||||
const subscriptions: Disposable[] = [];
|
const subscriptions: Disposable[] = [];
|
||||||
|
|
||||||
|
if (this._config.annotation.useCodeActions) {
|
||||||
this._diagnostics = languages.createDiagnosticCollection(DiagnosticCollectionName);
|
this._diagnostics = languages.createDiagnosticCollection(DiagnosticCollectionName);
|
||||||
subscriptions.push(this._diagnostics);
|
subscriptions.push(this._diagnostics);
|
||||||
|
|
||||||
subscriptions.push(languages.registerCodeActionsProvider(GitCodeActionsProvider.selector, new GitCodeActionsProvider(this.context, this.git)));
|
subscriptions.push(languages.registerCodeActionsProvider(GitCodeActionsProvider.selector, new GitCodeActionsProvider(this.context, this.git)));
|
||||||
|
}
|
||||||
|
|
||||||
subscriptions.push(window.onDidChangeTextEditorSelection(e => {
|
subscriptions.push(window.onDidChangeTextEditorSelection(e => {
|
||||||
const activeLine = e.selections[0].active.line;
|
const activeLine = e.selections[0].active.line;
|
||||||
|
|
||||||
this._diagnostics.clear();
|
this._diagnostics && this._diagnostics.clear();
|
||||||
|
|
||||||
this.git.getBlameForLine(e.textEditor.document.fileName, activeLine)
|
this.git.getBlameForLine(e.textEditor.document.fileName, activeLine)
|
||||||
.then(blame => {
|
.then(blame => {
|
||||||
if (!blame) return;
|
if (!blame) return;
|
||||||
|
|
||||||
// Add the bogus diagnostics to provide code actions for this sha
|
// Add the bogus diagnostics to provide code actions for this sha
|
||||||
this._diagnostics.set(editor.document.uri, [this._getDiagnostic(editor, activeLine, blame.commit.sha)]);
|
this._diagnostics && this._diagnostics.set(editor.document.uri, [this._getDiagnostic(editor, activeLine, blame.commit.sha)]);
|
||||||
|
|
||||||
this.applyHighlight(blame.commit.sha);
|
this.applyHighlight(blame.commit.sha);
|
||||||
});
|
});
|
||||||
@@ -156,60 +161,151 @@ class GitBlameEditorController extends Disposable {
|
|||||||
if (!blame || !blame.lines.length) return;
|
if (!blame || !blame.lines.length) return;
|
||||||
|
|
||||||
// HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- toggle whitespace off
|
// HACK: Until https://github.com/Microsoft/vscode/issues/11485 is fixed -- toggle whitespace off
|
||||||
this._toggleWhitespace = workspace.getConfiguration('editor').get('renderWhitespace') as boolean;
|
const whitespace = workspace.getConfiguration('editor').get<string>('renderWhitespace');
|
||||||
|
this._toggleWhitespace = whitespace !== 'false' && whitespace !== 'none';
|
||||||
if (this._toggleWhitespace) {
|
if (this._toggleWhitespace) {
|
||||||
commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace);
|
commands.executeCommand(BuiltInCommands.ToggleRenderWhitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastSha;
|
let blameDecorationOptions: DecorationOptions[]
|
||||||
const blameDecorationOptions: DecorationOptions[] = blame.lines.map(l => {
|
switch (this._config.annotation.style) {
|
||||||
let color = '#6b6b6b';
|
case BlameAnnotationStyle.Compact:
|
||||||
|
blameDecorationOptions = this._getCompactGutterDecorations(blame);
|
||||||
|
break;
|
||||||
|
case BlameAnnotationStyle.Expanded:
|
||||||
|
blameDecorationOptions = this._getExpandedGutterDecorations(blame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.editor.setDecorations(blameDecoration, blameDecorationOptions);
|
||||||
|
|
||||||
const c = blame.commits.get(l.sha);
|
sha = sha || blame.commits.values().next().value.sha;
|
||||||
if (c.previousSha) {
|
|
||||||
color = '#999999';
|
if (this._diagnostics) {
|
||||||
|
// Add the bogus diagnostics to provide code actions for this sha
|
||||||
|
const activeLine = this.editor.selection.active.line;
|
||||||
|
this._diagnostics.clear();
|
||||||
|
this._diagnostics.set(this.editor.document.uri, [this._getDiagnostic(this.editor, activeLine, sha)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.applyHighlight(sha);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_getCompactGutterDecorations(blame: IGitBlame): DecorationOptions[] {
|
||||||
|
let count = 0;
|
||||||
|
let lastSha;
|
||||||
|
return blame.lines.map(l => {
|
||||||
|
let color = l.previousSha ? '#999999' : '#6b6b6b';
|
||||||
|
let commit = blame.commits.get(l.sha);
|
||||||
|
let hoverMessage: string | Array<string> = [commit.message, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`];
|
||||||
|
|
||||||
|
if (l.sha.startsWith('00000000')) {
|
||||||
|
color = 'rgba(0, 188, 242, 0.6)';
|
||||||
|
hoverMessage = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let gutter = '';
|
let gutter = '';
|
||||||
if (lastSha !== l.sha || true) { // TODO: Add a config option
|
if (lastSha === l.sha) {
|
||||||
gutter = l.sha.substring(0, 8);
|
count++;
|
||||||
if (gutter === '00000000') {
|
if (count === 1) {
|
||||||
if (c.previousSha) {
|
gutter = `\\00a6\\00a0 ${this._getAuthor(commit, 17, true)}`;
|
||||||
const pc = blame.commits.get(c.previousSha);
|
} else if (count === 2) {
|
||||||
if (pc && pc.lines.find(_ => _.line === l.line)) {
|
gutter = `\\00a6\\00a0 ${this._getDate(commit, true)}`;
|
||||||
gutter = c.previousSha.substring(0, 8);
|
} else {
|
||||||
color = 'rgba(0, 188, 242, 0.6)';
|
gutter = '\\00a6\\00a0';
|
||||||
}
|
|
||||||
else {
|
|
||||||
color = 'rgba(127, 186, 0, 0.6)';
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
color = 'rgba(127, 186, 0, 0.6)';
|
count = 0;
|
||||||
}
|
gutter = commit.sha.substring(0, 8);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lastSha = l.sha;
|
lastSha = l.sha;
|
||||||
|
|
||||||
return <DecorationOptions>{
|
return <DecorationOptions>{
|
||||||
range: this.editor.document.validateRange(new Range(l.line, 0, l.line, 0)),
|
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')}`,
|
hoverMessage: [commit.message, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`],
|
||||||
renderOptions: { before: { color: color, contentText: gutter } }
|
renderOptions: { before: { color: color, contentText: gutter, width: '11em' } }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.editor.setDecorations(blameDecoration, blameDecorationOptions);
|
_getExpandedGutterDecorations(blame: IGitBlame): DecorationOptions[] {
|
||||||
|
let width = 0;
|
||||||
|
if (this._config.annotation.sha) {
|
||||||
|
width += 5;
|
||||||
|
}
|
||||||
|
if (this._config.annotation.date) {
|
||||||
|
if (width > 0) {
|
||||||
|
width += 7;
|
||||||
|
} else {
|
||||||
|
width += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._config.annotation.author) {
|
||||||
|
if (width > 5 + 6) {
|
||||||
|
width += 12;
|
||||||
|
} else if (width > 0) {
|
||||||
|
width += 11;
|
||||||
|
} else {
|
||||||
|
width += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sha = sha || blame.commits.values().next().value.sha;
|
return blame.lines.map(l => {
|
||||||
|
let color = l.previousSha ? '#999999' : '#6b6b6b';
|
||||||
|
let commit = blame.commits.get(l.sha);
|
||||||
|
let hoverMessage: string | Array<string> = [commit.message, `${commit.author}, ${moment(commit.date).format('MMMM Do, YYYY hh:MM a')}`];
|
||||||
|
|
||||||
// Add the bogus diagnostics to provide code actions for this sha
|
if (l.sha.startsWith('00000000')) {
|
||||||
const activeLine = this.editor.selection.active.line;
|
color = 'rgba(0, 188, 242, 0.6)';
|
||||||
this._diagnostics.clear();
|
hoverMessage = '';
|
||||||
this._diagnostics.set(this.editor.document.uri, [this._getDiagnostic(this.editor, activeLine, sha)]);
|
// if (l.previousSha) {
|
||||||
|
// let previousCommit = blame.commits.get(l.previousSha);
|
||||||
|
// if (previousCommit) {//} && previousCommit.lines.find(_ => _.line === l.originalLine)) {
|
||||||
|
// commit = previousCommit;
|
||||||
|
// color = 'rgba(0, 188, 242, 0.6)';
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// color = 'rgba(127, 186, 0, 0.6)';
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// color = 'rgba(127, 186, 0, 0.6)';
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
return this.applyHighlight(sha);
|
const gutter = this._getGutter(commit);
|
||||||
|
return <DecorationOptions>{
|
||||||
|
range: this.editor.document.validateRange(new Range(l.line, 0, l.line, 0)),
|
||||||
|
hoverMessage: hoverMessage,
|
||||||
|
renderOptions: { before: { color: color, contentText: gutter, width: `${width}em` } }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_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`;
|
||||||
|
}
|
||||||
|
return commit.author;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDate(commit: IGitCommit, force?: boolean) {
|
||||||
|
if (!force && !this._config.annotation.date) return '';
|
||||||
|
return moment(commit.date).format('MM/DD/YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
_getGutter(commit: IGitCommit) {
|
||||||
|
const author = this._getAuthor(commit);
|
||||||
|
const date = this._getDate(commit);
|
||||||
|
if (this._config.annotation.sha) {
|
||||||
|
return `${commit.sha.substring(0, 8)}${(date ? `\\00a0\\2022\\00a0 ${date}` : '')}${(author ? `\\00a0\\2022\\00a0 ${author}` : '')}`;
|
||||||
|
} else if (this._config.annotation.date) {
|
||||||
|
return `${date}${(author ? `\\00a0\\2022\\00a0 ${author}` : '')}`;
|
||||||
|
} else {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
applyHighlight(sha: string) {
|
applyHighlight(sha: string) {
|
||||||
return this._blame.then(blame => {
|
return this._blame.then(blame => {
|
||||||
if (!blame || !blame.lines.length) return;
|
if (!blame || !blame.lines.length) return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import {CancellationToken, CodeLens, CodeLensProvider, commands, DocumentSelector, ExtensionContext, Location, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, window} from 'vscode';
|
import {CancellationToken, CodeLens, CodeLensProvider, commands, DocumentSelector, ExtensionContext, Location, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, window, workspace} from 'vscode';
|
||||||
import {BuiltInCommands, Commands, DocumentSchemes, WorkspaceState} from './constants';
|
import {BuiltInCommands, Commands, DocumentSchemes, WorkspaceState} from './constants';
|
||||||
|
import {CodeLensCommand, ICodeLensesConfig} from './configuration';
|
||||||
import GitProvider, {IGitBlame, IGitBlameLines, IGitCommit} from './gitProvider';
|
import GitProvider, {IGitBlame, IGitBlameLines, IGitCommit} from './gitProvider';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@@ -15,7 +16,7 @@ export class GitRecentChangeCodeLens extends CodeLens {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitBlameCodeLens extends CodeLens {
|
export class GitAuthorsCodeLens extends CodeLens {
|
||||||
constructor(private git: GitProvider, public fileName: string, public symbolKind: SymbolKind, public blameRange: Range, range: Range) {
|
constructor(private git: GitProvider, public fileName: string, public symbolKind: SymbolKind, public blameRange: Range, range: Range) {
|
||||||
super(range);
|
super(range);
|
||||||
}
|
}
|
||||||
@@ -25,19 +26,15 @@ export class GitBlameCodeLens extends CodeLens {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export class GitHistoryCodeLens extends CodeLens {
|
|
||||||
// constructor(public repoPath: string, public fileName: string, range: Range) {
|
|
||||||
// super(range);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
export default class GitCodeLensProvider implements CodeLensProvider {
|
export default class GitCodeLensProvider implements CodeLensProvider {
|
||||||
static selector: DocumentSelector = { scheme: DocumentSchemes.File };
|
static selector: DocumentSelector = { scheme: DocumentSchemes.File };
|
||||||
|
|
||||||
// private hasGitHistoryExtension: boolean;
|
private _config: ICodeLensesConfig;
|
||||||
|
private _hasGitHistoryExtension: boolean;
|
||||||
|
|
||||||
constructor(context: ExtensionContext, private git: GitProvider) {
|
constructor(context: ExtensionContext, private git: GitProvider) {
|
||||||
// this.hasGitHistoryExtension = context.workspaceState.get(WorkspaceState.HasGitHistoryExtension, false);
|
this._config = workspace.getConfiguration('gitlens').get<ICodeLensesConfig>('codeLens');
|
||||||
|
this._hasGitHistoryExtension = context.workspaceState.get(WorkspaceState.HasGitHistoryExtension, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable<CodeLens[]> {
|
provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable<CodeLens[]> {
|
||||||
@@ -55,11 +52,12 @@ export default class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
// Check if we have a lens for the whole document -- if not add one
|
// Check if we have a lens for the whole document -- if not add one
|
||||||
if (!lenses.find(l => l.range.start.line === 0 && l.range.end.line === 0)) {
|
if (!lenses.find(l => l.range.start.line === 0 && l.range.end.line === 0)) {
|
||||||
const blameRange = document.validateRange(new Range(0, 1000000, 1000000, 1000000));
|
const blameRange = document.validateRange(new Range(0, 1000000, 1000000, 1000000));
|
||||||
|
if (this._config.recentChange.enabled) {
|
||||||
lenses.push(new GitRecentChangeCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 0, 0, blameRange.start.character)));
|
lenses.push(new GitRecentChangeCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 0, 0, blameRange.start.character)));
|
||||||
lenses.push(new GitBlameCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 1, 0, blameRange.start.character)));
|
}
|
||||||
// if (this.hasGitHistoryExtension) {
|
if (this._config.authors.enabled) {
|
||||||
// lenses.push(new GitHistoryCodeLens(this.git.repoPath, fileName, new Range(0, 1, 0, blameRange.start.character)));
|
lenses.push(new GitAuthorsCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 1, 0, blameRange.start.character)));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lenses;
|
return lenses;
|
||||||
@@ -107,57 +105,72 @@ export default class GitCodeLensProvider implements CodeLensProvider {
|
|||||||
startChar += Math.floor(symbol.name.length / 2);
|
startChar += Math.floor(symbol.name.length / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._config.recentChange.enabled) {
|
||||||
lenses.push(new GitRecentChangeCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar))));
|
lenses.push(new GitRecentChangeCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar))));
|
||||||
startChar++;
|
startChar++;
|
||||||
if (multiline) {
|
|
||||||
lenses.push(new GitBlameCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar))));
|
|
||||||
startChar++;
|
|
||||||
}
|
}
|
||||||
// if (this.hasGitHistoryExtension) {
|
if (multiline && this._config.authors.enabled) {
|
||||||
// lenses.push(new GitHistoryCodeLens(this.git.repoPath, fileName, line.range.with(new Position(line.range.start.line, startChar))));
|
lenses.push(new GitAuthorsCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar))));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveCodeLens(lens: CodeLens, token: CancellationToken): Thenable<CodeLens> {
|
resolveCodeLens(lens: CodeLens, token: CancellationToken): Thenable<CodeLens> {
|
||||||
if (lens instanceof GitRecentChangeCodeLens) return this._resolveGitRecentChangeCodeLens(lens, token);
|
if (lens instanceof GitRecentChangeCodeLens) return this._resolveGitRecentChangeCodeLens(lens, token);
|
||||||
if (lens instanceof GitBlameCodeLens) return this._resolveGitBlameCodeLens(lens, token);
|
if (lens instanceof GitAuthorsCodeLens) return this._resolveGitAuthorsCodeLens(lens, token);
|
||||||
// if (lens instanceof GitHistoryCodeLens) return this._resolveGitHistoryCodeLens(lens, token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_resolveGitRecentChangeCodeLens(lens: GitRecentChangeCodeLens, token: CancellationToken): Thenable<CodeLens> {
|
_resolveGitRecentChangeCodeLens(lens: GitRecentChangeCodeLens, token: CancellationToken): Thenable<CodeLens> {
|
||||||
return lens.getBlame().then(blame => {
|
return lens.getBlame().then(blame => {
|
||||||
const recentCommit = blame.commits.values().next().value;
|
const recentCommit = blame.commits.values().next().value;
|
||||||
|
const title = `${recentCommit.author}, ${moment(recentCommit.date).fromNow()}`; // - ${SymbolKind[lens.symbolKind]}(${lens.blameRange.start.line + 1}-${lens.blameRange.end.line + 1})`;
|
||||||
|
switch (this._config.recentChange.command) {
|
||||||
|
case CodeLensCommand.BlameAnnotate: return this._applyBlameAnnotateCommand<GitRecentChangeCodeLens>(title, lens, blame);
|
||||||
|
case CodeLensCommand.BlameExplorer: return this._applyBlameExplorerCommand<GitRecentChangeCodeLens>(title, lens, blame);
|
||||||
|
case CodeLensCommand.GitHistory: return this._applyGitHistoryCommand<GitRecentChangeCodeLens>(title, lens, blame);
|
||||||
|
default: return lens;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveGitAuthorsCodeLens(lens: GitAuthorsCodeLens, token: CancellationToken): Thenable<CodeLens> {
|
||||||
|
return lens.getBlame().then(blame => {
|
||||||
|
const count = blame.authors.size;
|
||||||
|
const title = `${count} ${count > 1 ? 'authors' : 'author'} (${blame.authors.values().next().value.name}${count > 1 ? ' and others' : ''})`;
|
||||||
|
switch (this._config.authors.command) {
|
||||||
|
case CodeLensCommand.BlameAnnotate: return this._applyBlameAnnotateCommand<GitAuthorsCodeLens>(title, lens, blame);
|
||||||
|
case CodeLensCommand.BlameExplorer: return this._applyBlameExplorerCommand<GitAuthorsCodeLens>(title, lens, blame);
|
||||||
|
case CodeLensCommand.GitHistory: return this._applyGitHistoryCommand<GitAuthorsCodeLens>(title, lens, blame);
|
||||||
|
default: return lens;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_applyBlameAnnotateCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines, sha?: string) {
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: `${recentCommit.author}, ${moment(recentCommit.date).fromNow()}`, // - ${SymbolKind[lens.symbolKind]}(${lens.blameRange.start.line + 1}-${lens.blameRange.end.line + 1})`,
|
title: title,
|
||||||
|
command: Commands.ToggleBlame,
|
||||||
|
arguments: [Uri.file(lens.fileName), sha]
|
||||||
|
};
|
||||||
|
return lens;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applyBlameExplorerCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines) {
|
||||||
|
lens.command = {
|
||||||
|
title: title,
|
||||||
command: Commands.ShowBlameHistory,
|
command: Commands.ShowBlameHistory,
|
||||||
arguments: [Uri.file(lens.fileName), lens.blameRange, lens.range.start]
|
arguments: [Uri.file(lens.fileName), lens.blameRange, lens.range.start]
|
||||||
};
|
};
|
||||||
return lens;
|
return lens;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_resolveGitBlameCodeLens(lens: GitBlameCodeLens, token: CancellationToken): Thenable<CodeLens> {
|
_applyGitHistoryCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(title: string, lens: T, blame: IGitBlameLines) {
|
||||||
return lens.getBlame().then(blame => {
|
if (!this._hasGitHistoryExtension) return this._applyBlameExplorerCommand(title, lens, blame);
|
||||||
const editor = window.activeTextEditor;
|
|
||||||
const activeLine = editor.selection.active.line;
|
|
||||||
|
|
||||||
const count = blame.authors.size;
|
|
||||||
lens.command = {
|
lens.command = {
|
||||||
title: `${count} ${count > 1 ? 'authors' : 'author'} (${blame.authors.values().next().value.name}${count > 1 ? ' and others' : ''})`,
|
title: title,
|
||||||
command: Commands.ToggleBlame,
|
command: 'git.viewFileHistory',
|
||||||
arguments: [Uri.file(lens.fileName), blame.allLines[activeLine].sha]
|
arguments: [Uri.file(lens.fileName)]
|
||||||
};
|
};
|
||||||
return lens;
|
return lens;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// _resolveGitHistoryCodeLens(lens: GitHistoryCodeLens, token: CancellationToken): Thenable<CodeLens> {
|
|
||||||
// // TODO: Play with this more -- get this to open the correct diff to the right place
|
|
||||||
// lens.command = {
|
|
||||||
// title: `View History`,
|
|
||||||
// command: 'git.viewFileHistory', // viewLineHistory
|
|
||||||
// arguments: [Uri.file(lens.fileName)]
|
|
||||||
// };
|
|
||||||
// return Promise.resolve(lens);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ import * as ignore from 'ignore';
|
|||||||
|
|
||||||
const commitMessageMatcher = /^([\^0-9a-fA-F]{7})\s(.*)$/gm;
|
const commitMessageMatcher = /^([\^0-9a-fA-F]{7})\s(.*)$/gm;
|
||||||
const blamePorcelainMatcher = /^([\^0-9a-fA-F]{40})\s([0-9]+)\s([0-9]+)(?:\s([0-9]+))?$\n(?:^author\s(.*)$\n^author-mail\s(.*)$\n^author-time\s(.*)$\n^author-tz\s(.*)$\n^committer\s(.*)$\n^committer-mail\s(.*)$\n^committer-time\s(.*)$\n^committer-tz\s(.*)$\n^summary\s(.*)$\n(?:^previous\s(.*)?\s(.*)$\n)?^filename\s(.*)$\n)?^(.*)$/gm;
|
const blamePorcelainMatcher = /^([\^0-9a-fA-F]{40})\s([0-9]+)\s([0-9]+)(?:\s([0-9]+))?$\n(?:^author\s(.*)$\n^author-mail\s(.*)$\n^author-time\s(.*)$\n^author-tz\s(.*)$\n^committer\s(.*)$\n^committer-mail\s(.*)$\n^committer-time\s(.*)$\n^committer-tz\s(.*)$\n^summary\s(.*)$\n(?:^previous\s(.*)?\s(.*)$\n)?^filename\s(.*)$\n)?^(.*)$/gm;
|
||||||
|
const blameLinePorcelainMatcher = /^([\^0-9a-fA-F]{40})\s([0-9]+)\s([0-9]+)(?:\s([0-9]+))?$\n^author\s(.*)$\n^author-mail\s(.*)$\n^author-time\s(.*)$\n^author-tz\s(.*)$\n^committer\s(.*)$\n^committer-mail\s(.*)$\n^committer-time\s(.*)$\n^committer-tz\s(.*)$\n^summary\s(.*)$\n(?:^previous\s(.*)?\s(.*)$\n)?^filename\s(.*)$\n^(.*)$/gm;
|
||||||
|
|
||||||
interface IBlameCacheEntry {
|
interface IBlameCacheEntry {
|
||||||
//date: Date;
|
//date: Date;
|
||||||
@@ -70,6 +71,7 @@ export default class GitProvider extends Disposable {
|
|||||||
subscriptions.push(workspace.onDidCloseTextDocument(d => this._removeCachedBlame(d.fileName, RemoveCacheReason.DocumentClosed)));
|
subscriptions.push(workspace.onDidCloseTextDocument(d => this._removeCachedBlame(d.fileName, RemoveCacheReason.DocumentClosed)));
|
||||||
subscriptions.push(workspace.onDidSaveTextDocument(d => this._removeCachedBlameFn(d.fileName, RemoveCacheReason.DocumentSaved)));
|
subscriptions.push(workspace.onDidSaveTextDocument(d => this._removeCachedBlameFn(d.fileName, RemoveCacheReason.DocumentSaved)));
|
||||||
subscriptions.push(workspace.onDidChangeTextDocument(e => this._removeCachedBlameFn(e.document.fileName, RemoveCacheReason.DocumentChanged)));
|
subscriptions.push(workspace.onDidChangeTextDocument(e => this._removeCachedBlameFn(e.document.fileName, RemoveCacheReason.DocumentChanged)));
|
||||||
|
subscriptions.push(workspace.onDidChangeConfiguration(() => this._registerCodeLensProvider()));
|
||||||
|
|
||||||
this._disposable = Disposable.from(...subscriptions);
|
this._disposable = Disposable.from(...subscriptions);
|
||||||
}
|
}
|
||||||
@@ -128,6 +130,7 @@ export default class GitProvider extends Disposable {
|
|||||||
console.log('[GitLens]', `Skipping blame; ${fileName} is gitignored`);
|
console.log('[GitLens]', `Skipping blame; ${fileName} is gitignored`);
|
||||||
blame = GitProvider.BlameEmptyPromise;
|
blame = GitProvider.BlameEmptyPromise;
|
||||||
} else {
|
} else {
|
||||||
|
//blame = Git.blameLinePorcelain(fileName, this.repoPath)
|
||||||
blame = Git.blamePorcelain(fileName, this.repoPath)
|
blame = Git.blamePorcelain(fileName, this.repoPath)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
@@ -137,8 +140,10 @@ export default class GitProvider extends Disposable {
|
|||||||
const lines: Array<IGitCommitLine> = [];
|
const lines: Array<IGitCommitLine> = [];
|
||||||
|
|
||||||
let m: Array<string>;
|
let m: Array<string>;
|
||||||
|
//while ((m = blameLinePorcelainMatcher.exec(data)) != null) {
|
||||||
while ((m = blamePorcelainMatcher.exec(data)) != null) {
|
while ((m = blamePorcelainMatcher.exec(data)) != null) {
|
||||||
const sha = m[1].substring(0, 8);
|
const sha = m[1].substring(0, 8);
|
||||||
|
const previousSha = m[14];
|
||||||
let commit = commits.get(sha);
|
let commit = commits.get(sha);
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
const authorName = m[5].trim();
|
const authorName = m[5].trim();
|
||||||
@@ -158,7 +163,6 @@ export default class GitProvider extends Disposable {
|
|||||||
commit.originalFileName = originalFileName;
|
commit.originalFileName = originalFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousSha = m[14];
|
|
||||||
if (previousSha) {
|
if (previousSha) {
|
||||||
commit.previousSha = previousSha.substring(0, 8);
|
commit.previousSha = previousSha.substring(0, 8);
|
||||||
commit.previousFileName = m[15];
|
commit.previousFileName = m[15];
|
||||||
@@ -174,6 +178,10 @@ export default class GitProvider extends Disposable {
|
|||||||
//code: m[17]
|
//code: m[17]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previousSha) {
|
||||||
|
line.previousSha = previousSha.substring(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
commit.lines.push(line);
|
commit.lines.push(line);
|
||||||
lines.push(line);
|
lines.push(line);
|
||||||
}
|
}
|
||||||
@@ -485,6 +493,7 @@ class GitCommit implements IGitCommit {
|
|||||||
|
|
||||||
export interface IGitCommitLine {
|
export interface IGitCommitLine {
|
||||||
sha: string;
|
sha: string;
|
||||||
|
previousSha?: string;
|
||||||
line: number;
|
line: number;
|
||||||
originalLine: number;
|
originalLine: number;
|
||||||
code?: string;
|
code?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user