mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-01-17 17:25:51 -05:00
Major refactor/rework -- many new features and breaking changes
Adds all-new, beautiful, highly customizable and themeable, file blame annotations Adds all-new configurability and themeability to the current line blame annotations Adds all-new configurability to the status bar blame information Adds all-new configurability over which commands are added to which menus via the `gitlens.advanced.menus` setting Adds better configurability over where Git code lens will be shown -- both by default and per language Adds an all-new `changes` (diff) hover annotation to the current line - provides instant access to the line's previous version Adds `Toggle Line Blame Annotations` command (`gitlens.toggleLineBlame`) - toggles the current line blame annotations on and off Adds `Show Line Blame Annotations` command (`gitlens.showLineBlame`) - shows the current line blame annotations Adds `Toggle File Blame Annotations` command (`gitlens.toggleFileBlame`) - toggles the file blame annotations on and off Adds `Show File Blame Annotations` command (`gitlens.showFileBlame`) - shows the file blame annotations Adds `Open File in Remote` command (`gitlens.openFileInRemote`) to the `editor/title` context menu Adds `Open Repo in Remote` command (`gitlens.openRepoInRemote`) to the `editor/title` context menu Changes the position of the `Open File in Remote` command (`gitlens.openFileInRemote`) in the context menus - now in the `navigation` group Changes the `Toggle Git Code Lens` command (`gitlens.toggleCodeLens`) to always toggle the Git code lens on and off Removes the on-demand `trailing` file blame annotations -- didn't work out and just ended up with a ton of visual noise Removes `Toggle Blame Annotations` command (`gitlens.toggleBlame`) - replaced by the `Toggle File Blame Annotations` command (`gitlens.toggleFileBlame`) Removes `Show Blame Annotations` command (`gitlens.showBlame`) - replaced by the `Show File Blame Annotations` command (`gitlens.showFileBlame`)
This commit is contained in:
160
src/git/formatters/commit.ts
Normal file
160
src/git/formatters/commit.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
'use strict';
|
||||
import { Strings } from '../../system';
|
||||
import { GitCommit } from '../models/commit';
|
||||
import { IGitDiffLine } from '../models/diff';
|
||||
import * as moment from 'moment';
|
||||
|
||||
export interface ICommitFormatOptions {
|
||||
dateFormat?: string | null;
|
||||
tokenOptions?: {
|
||||
ago?: Strings.ITokenOptions;
|
||||
author?: Strings.ITokenOptions;
|
||||
authorAgo?: Strings.ITokenOptions;
|
||||
date?: Strings.ITokenOptions;
|
||||
message?: Strings.ITokenOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export class CommitFormatter {
|
||||
|
||||
private _options: ICommitFormatOptions;
|
||||
|
||||
constructor(private commit: GitCommit, options?: ICommitFormatOptions) {
|
||||
options = options || {};
|
||||
if (options.tokenOptions == null) {
|
||||
options.tokenOptions = {};
|
||||
}
|
||||
|
||||
if (options.dateFormat == null) {
|
||||
options.dateFormat = 'MMMM Do, YYYY h:MMa';
|
||||
}
|
||||
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
get ago() {
|
||||
const ago = moment(this.commit.date).fromNow();
|
||||
return this._padOrTruncate(ago, this._options.tokenOptions!.ago);
|
||||
}
|
||||
|
||||
get author() {
|
||||
const author = this.commit.author;
|
||||
return this._padOrTruncate(author, this._options.tokenOptions!.author);
|
||||
}
|
||||
|
||||
get authorAgo() {
|
||||
const authorAgo = `${this.commit.author}, ${moment(this.commit.date).fromNow()}`;
|
||||
return this._padOrTruncate(authorAgo, this._options.tokenOptions!.authorAgo);
|
||||
}
|
||||
|
||||
get date() {
|
||||
const date = moment(this.commit.date).format(this._options.dateFormat!);
|
||||
return this._padOrTruncate(date, this._options.tokenOptions!.date);
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.commit.shortSha;
|
||||
}
|
||||
|
||||
get message() {
|
||||
const message = this.commit.isUncommitted ? 'Uncommitted change' : this.commit.message;
|
||||
return this._padOrTruncate(message, this._options.tokenOptions!.message);
|
||||
}
|
||||
|
||||
get sha() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
private collapsableWhitespace: number = 0;
|
||||
|
||||
private _padOrTruncate(s: string, options: Strings.ITokenOptions | undefined) {
|
||||
// NOTE: the collapsable whitespace logic relies on the javascript template evaluation to be left to right
|
||||
if (options === undefined) {
|
||||
options = {
|
||||
truncateTo: undefined,
|
||||
padDirection: 'left',
|
||||
collapseWhitespace: false
|
||||
};
|
||||
}
|
||||
|
||||
let max = options.truncateTo;
|
||||
|
||||
if (max === undefined) {
|
||||
if (this.collapsableWhitespace === 0) return s;
|
||||
|
||||
// If we have left over whitespace make sure it gets re-added
|
||||
const diff = this.collapsableWhitespace - s.length;
|
||||
this.collapsableWhitespace = 0;
|
||||
|
||||
if (diff <= 0) return s;
|
||||
if (options.truncateTo === undefined) return s;
|
||||
return Strings.padLeft(s, diff);
|
||||
}
|
||||
|
||||
max += this.collapsableWhitespace;
|
||||
this.collapsableWhitespace = 0;
|
||||
|
||||
const diff = max - s.length;
|
||||
if (diff > 0) {
|
||||
if (options.collapseWhitespace) {
|
||||
this.collapsableWhitespace = diff;
|
||||
}
|
||||
|
||||
if (options.padDirection === 'left') return Strings.padLeft(s, max);
|
||||
|
||||
if (options.collapseWhitespace) {
|
||||
max -= diff;
|
||||
}
|
||||
return Strings.padRight(s, max);
|
||||
}
|
||||
|
||||
if (diff < 0) return Strings.truncate(s, max);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static fromTemplate(template: string, commit: GitCommit, dateFormat: string | null): string;
|
||||
static fromTemplate(template: string, commit: GitCommit, options?: ICommitFormatOptions): string;
|
||||
static fromTemplate(template: string, commit: GitCommit, dateFormatOrOptions?: string | null | ICommitFormatOptions): string;
|
||||
static fromTemplate(template: string, commit: GitCommit, dateFormatOrOptions?: string | null | ICommitFormatOptions): string {
|
||||
let options: ICommitFormatOptions | undefined = undefined;
|
||||
if (dateFormatOrOptions == null || typeof dateFormatOrOptions === 'string') {
|
||||
const tokenOptions = Strings.getTokensFromTemplate(template)
|
||||
.reduce((map, token) => {
|
||||
map[token.key] = token.options;
|
||||
return map;
|
||||
}, {} as { [token: string]: ICommitFormatOptions });
|
||||
|
||||
options = {
|
||||
dateFormat: dateFormatOrOptions,
|
||||
tokenOptions: tokenOptions
|
||||
};
|
||||
}
|
||||
else {
|
||||
options = dateFormatOrOptions;
|
||||
}
|
||||
|
||||
return Strings.interpolateLazy(template, new CommitFormatter(commit, options));
|
||||
}
|
||||
|
||||
static toHoverAnnotation(commit: GitCommit, dateFormat: string = 'MMMM Do, YYYY h:MMa'): string | string[] {
|
||||
const message = commit.isUncommitted ? '' : `\n\n> ${commit.message.replace(/\n/g, '\n>\n> ')}`;
|
||||
return `\`${commit.shortSha}\` __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`;
|
||||
}
|
||||
|
||||
static toHoverDiff(commit: GitCommit, previous: IGitDiffLine | undefined, current: IGitDiffLine | undefined): string | undefined {
|
||||
if (previous === undefined && current === undefined) return undefined;
|
||||
|
||||
const codeDiff = this._getCodeDiff(previous, current);
|
||||
return commit.isUncommitted
|
||||
? `\`Changes\` \u2014 _uncommitted_\n${codeDiff}`
|
||||
: `\`Changes\` \u2014 \`${commit.previousShortSha}\` \u2194 \`${commit.shortSha}\`\n${codeDiff}`;
|
||||
}
|
||||
|
||||
private static _getCodeDiff(previous: IGitDiffLine | undefined, current: IGitDiffLine | undefined): string {
|
||||
return `\`\`\`
|
||||
- ${previous === undefined ? '' : previous.line.trim()}
|
||||
+ ${current === undefined ? '' : current.line.trim()}
|
||||
\`\`\``;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
export interface IGitDiffLine {
|
||||
line: string;
|
||||
state: 'added' | 'removed' | 'unchanged';
|
||||
}
|
||||
|
||||
export interface IGitDiffChunk {
|
||||
current: (string | undefined)[];
|
||||
current: (IGitDiffLine | undefined)[];
|
||||
currentStart: number;
|
||||
currentEnd: number;
|
||||
|
||||
previous: (string | undefined)[];
|
||||
previous: (IGitDiffLine | undefined)[];
|
||||
previousStart: number;
|
||||
previousEnd: number;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export class GitBlameParser {
|
||||
switch (lineParts[0]) {
|
||||
case 'author':
|
||||
entry.author = Git.isUncommitted(entry.sha)
|
||||
? 'Uncommitted'
|
||||
? 'You'
|
||||
: lineParts.slice(1).join(' ').trim();
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
import { IGitDiff, IGitDiffChunk } from './../git';
|
||||
import { IGitDiff, IGitDiffChunk, IGitDiffLine } from './../git';
|
||||
|
||||
const unifiedDiffRegex = /^@@ -([\d]+),([\d]+) [+]([\d]+),([\d]+) @@([\s\S]*?)(?=^@@)/gm;
|
||||
|
||||
@@ -21,23 +21,29 @@ export class GitDiffParser {
|
||||
const chunk = match[5];
|
||||
const lines = chunk.split('\n').slice(1);
|
||||
|
||||
const current = [];
|
||||
const previous = [];
|
||||
const current: (IGitDiffLine | undefined)[] = [];
|
||||
const previous: (IGitDiffLine | undefined)[] = [];
|
||||
for (const l of lines) {
|
||||
switch (l[0]) {
|
||||
case '+':
|
||||
current.push(` ${l.substring(1)}`);
|
||||
current.push({
|
||||
line: ` ${l.substring(1)}`,
|
||||
state: 'added'
|
||||
});
|
||||
previous.push(undefined);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
current.push(undefined);
|
||||
previous.push(` ${l.substring(1)}`);
|
||||
previous.push({
|
||||
line: ` ${l.substring(1)}`,
|
||||
state: 'removed'
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
current.push(l);
|
||||
previous.push(l);
|
||||
current.push({ line: l, state: 'unchanged' });
|
||||
previous.push({ line: l, state: 'unchanged' });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export class GitLogParser {
|
||||
switch (lineParts[0]) {
|
||||
case 'author':
|
||||
entry.author = Git.isUncommitted(entry.sha)
|
||||
? 'Uncommitted'
|
||||
? 'You'
|
||||
: lineParts.slice(1).join(' ').trim();
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user