Skip to content

Commit

Permalink
Closes #493 - Adds changes to commits in explorers
Browse files Browse the repository at this point in the history
Adds new ${changes} and ${changesShort} template tokens
Adds support for prefixes and suffixes around tokens
Fixes missing/mismatched token option issues
  • Loading branch information
eamodio committed Sep 9, 2018
1 parent b58dc49 commit 2d97726
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 104 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
},
"gitlens.explorers.commitFormat": {
"type": "string",
"default": "${message} • ${authorAgoOrDate} (${id})",
"default": "${message} • ${authorAgoOrDate}${ (id)}",
"description": "Specifies the format of committed changes in the `GitLens` and `GitLens Results` explorers\nAvailable tokens\n ${id} - commit id\n ${author} - commit author\n ${message} - commit message\n ${ago} - relative commit date (e.g. 1 day ago)\n ${date} - formatted commit date (format specified by `gitlens.defaultDateFormat`)\\n ${agoOrDate} - commit date specified by `gitlens.defaultDateStyle`\n ${authorAgo} - commit author, relative commit date\n ${authorAgoOrDate} - commit author, commit date specified by `gitlens.defaultDateStyle`\nSee https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting",
"scope": "window"
},
Expand All @@ -469,7 +469,7 @@
},
"gitlens.explorers.statusFileFormat": {
"type": "string",
"default": "${working}${filePath}",
"default": "${working }${filePath}",
"description": "Specifies the format of the status of a working or committed file in the `GitLens` and `GitLens Results` explorers\nAvailable tokens\n ${directory} - directory name\n ${file} - file name\n ${filePath} - formatted file name and path\n ${path} - full file path\n ${working} - optional indicator if the file is uncommitted",
"scope": "window"
},
Expand Down
29 changes: 26 additions & 3 deletions src/git/formatters/commitFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { DateStyle } from '../../configuration';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { Strings } from '../../system';
import { GitCommit } from '../models/commit';
import { GitCommit, GitCommitType } from '../models/commit';
import { GitLogCommit } from '../models/models';
import { Formatter, IFormatOptions } from './formatter';

const emojiMap: { [key: string]: string } = require('../../../emoji/emojis.json');
Expand All @@ -19,7 +20,10 @@ export interface ICommitFormatOptions extends IFormatOptions {
author?: Strings.ITokenOptions;
authorAgo?: Strings.ITokenOptions;
authorAgoOrDate?: Strings.ITokenOptions;
changes?: Strings.ITokenOptions;
changesShort?: Strings.ITokenOptions;
date?: Strings.ITokenOptions;
id?: Strings.ITokenOptions;
message?: Strings.ITokenOptions;
};
}
Expand Down Expand Up @@ -59,15 +63,34 @@ export class CommitFormatter extends Formatter<GitCommit, ICommitFormatOptions>

get authorAgoOrDate() {
const authorAgo = `${this._item.author}, ${this._agoOrDate}`;
return this._padOrTruncate(authorAgo, this._options.tokenOptions!.authorAgo);
return this._padOrTruncate(authorAgo, this._options.tokenOptions!.authorAgoOrDate);
}

get changes() {
if (!(this._item instanceof GitLogCommit) || this._item.type === GitCommitType.File) {
return this._padOrTruncate('', this._options.tokenOptions!.changes);
}

return this._padOrTruncate(this._item.getFormattedDiffStatus(), this._options.tokenOptions!.changes);
}

get changesShort() {
if (!(this._item instanceof GitLogCommit) || this._item.type === GitCommitType.File) {
return this._padOrTruncate('', this._options.tokenOptions!.changesShort);
}

return this._padOrTruncate(
this._item.getFormattedDiffStatus({ compact: true, separator: '' }),
this._options.tokenOptions!.changesShort
);
}

get date() {
return this._padOrTruncate(this._date, this._options.tokenOptions!.date);
}

get id() {
return this._item.shortSha;
return this._padOrTruncate(this._item.shortSha || '', this._options.tokenOptions!.id);
}

get message() {
Expand Down
83 changes: 49 additions & 34 deletions src/git/formatters/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,50 +41,62 @@ export abstract class Formatter<TItem = any, TOptions extends IFormatOptions = I
private collapsableWhitespace: number = 0;

protected _padOrTruncate(s: string, options: Strings.ITokenOptions | undefined) {
if (s === '') return s;

// NOTE: the collapsable whitespace logic relies on the javascript template evaluation to be left to right
if (options === undefined) {
options = {
truncateTo: undefined,
collapseWhitespace: false,
padDirection: 'left',
collapseWhitespace: false
prefix: undefined,
suffix: undefined,
truncateTo: undefined
};
}

let max = options.truncateTo;

if (max === undefined) {
if (this.collapsableWhitespace === 0) return s;
if (this.collapsableWhitespace !== 0) {
const width = Strings.getWidth(s);

const width = Strings.getWidth(s);
// If we have left over whitespace make sure it gets re-added
const diff = this.collapsableWhitespace - width;
this.collapsableWhitespace = 0;

// If we have left over whitespace make sure it gets re-added
const diff = this.collapsableWhitespace - width;
this.collapsableWhitespace = 0;

if (diff <= 0) return s;
if (options.truncateTo === undefined) return s;
return Strings.padLeft(s, diff, undefined, width);
if (diff > 0 && options.truncateTo !== undefined) {
s = Strings.padLeft(s, diff, undefined, width);
}
}
}
else {
max += this.collapsableWhitespace;
this.collapsableWhitespace = 0;

max += this.collapsableWhitespace;
this.collapsableWhitespace = 0;

const width = Strings.getWidth(s);
const diff = max - width;
if (diff > 0) {
if (options.collapseWhitespace) {
this.collapsableWhitespace = diff;
const width = Strings.getWidth(s);
const diff = max - width;
if (diff > 0) {
if (options.collapseWhitespace) {
this.collapsableWhitespace = diff;
}

if (options.padDirection === 'left') {
s = Strings.padLeft(s, max, undefined, width);
}
else {
if (options.collapseWhitespace) {
max -= diff;
}
s = Strings.padRight(s, max, undefined, width);
}
}

if (options.padDirection === 'left') return Strings.padLeft(s, max, undefined, width);

if (options.collapseWhitespace) {
max -= diff;
else if (diff < 0) {
s = Strings.truncate(s, max, undefined, width);
}
return Strings.padRight(s, max, undefined, width);
}

if (diff < 0) return Strings.truncate(s, max, undefined, width);
if (options.prefix || options.suffix) {
s = `${options.prefix || ''}${s}${options.suffix || ''}`;
}

return s;
}
Expand All @@ -107,6 +119,15 @@ export abstract class Formatter<TItem = any, TOptions extends IFormatOptions = I

let options: TOptions | undefined = undefined;
if (dateFormatOrOptions == null || typeof dateFormatOrOptions === 'string') {
options = {
dateFormat: dateFormatOrOptions
} as TOptions;
}
else {
options = dateFormatOrOptions;
}

if (options.tokenOptions == null) {
const tokenOptions = Strings.getTokensFromTemplate(template).reduce(
(map, token) => {
map[token.key] = token.options;
Expand All @@ -115,13 +136,7 @@ export abstract class Formatter<TItem = any, TOptions extends IFormatOptions = I
{} as { [token: string]: Strings.ITokenOptions | undefined }
);

options = {
dateFormat: dateFormatOrOptions,
tokenOptions: tokenOptions
} as TOptions;
}
else {
options = dateFormatOrOptions;
options.tokenOptions = tokenOptions;
}

if (this._formatter === undefined) {
Expand Down
8 changes: 6 additions & 2 deletions src/git/formatters/statusFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ export interface IStatusFormatOptions extends IFormatOptions {
filePath?: Strings.ITokenOptions;
path?: Strings.ITokenOptions;
status?: Strings.ITokenOptions;
working?: Strings.ITokenOptions;
};
}

export class StatusFileFormatter extends Formatter<IGitStatusFile, IStatusFormatOptions> {
get directory() {
const directory = GitStatusFile.getFormattedDirectory(this._item, false, this._options.relativePath);
return this._padOrTruncate(directory, this._options.tokenOptions!.file);
return this._padOrTruncate(directory, this._options.tokenOptions!.directory);
}

get file() {
Expand All @@ -45,7 +46,10 @@ export class StatusFileFormatter extends Formatter<IGitStatusFile, IStatusFormat

get working() {
const commit = (this._item as IGitStatusFileWithCommit).commit;
return commit !== undefined && commit.isUncommitted ? `${GlyphChars.Pencil} ${GlyphChars.Space}` : '';
return this._padOrTruncate(
commit !== undefined && commit.isUncommitted ? GlyphChars.Pencil : '',
this._options.tokenOptions!.working
);
}

static fromTemplate(template: string, status: IGitStatusFile, dateFormat: string | null): string;
Expand Down
81 changes: 63 additions & 18 deletions src/git/models/logCommit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,72 @@ export class GitLogCommit extends GitCommit {
return this.isFile && this.previousSha ? this.previousSha : `${this.sha}^`;
}

getDiffStatus(): string {
let added = 0;
let deleted = 0;
let changed = 0;

for (const f of this.fileStatuses) {
switch (f.status) {
case 'A':
case '?':
added++;
break;
case 'D':
deleted++;
break;
default:
changed++;
break;
private _diff?: {
added: number;
deleted: number;
changed: number;
};

getDiffStatus() {
if (this._diff === undefined) {
this._diff = {
added: 0,
deleted: 0,
changed: 0
};

if (this.fileStatuses.length !== 0) {
for (const f of this.fileStatuses) {
switch (f.status) {
case 'A':
case '?':
this._diff.added++;
break;
case 'D':
this._diff.deleted++;
break;
default:
this._diff.changed++;
break;
}
}
}
}

return this._diff;
}

getFormattedDiffStatus(
options: {
compact?: boolean;
empty?: string;
expand?: boolean;
prefix?: string;
separator?: string;
suffix?: string;
} = {}
): string {
const { added, changed, deleted } = this.getDiffStatus();
if (added === 0 && changed === 0 && deleted === 0) return options.empty || '';

options = { compact: true, empty: '', prefix: '', separator: ' ', suffix: '', ...options };
if (options.expand) {
let status = '';
if (added) {
status += `${Strings.pluralize('file', added)} added`;
}
if (changed) {
status += `${status === '' ? '' : options.separator}${Strings.pluralize('file', changed)} changed`;
}
if (deleted) {
status += `${status === '' ? '' : options.separator}${Strings.pluralize('file', deleted)} deleted`;
}
return `${options.prefix}${status}${options.suffix}`;
}

return `+${added} ~${changed} -${deleted}`;
return `${options.prefix}${options.compact && added === 0 ? '' : `+${added}${options.separator}`}${
options.compact && changed === 0 ? '' : `~${changed}${options.separator}`
}${options.compact && deleted === 0 ? '' : `-${deleted}`}${options.suffix}`;
}

toFileCommit(fileName: string): GitLogCommit | undefined;
Expand Down

0 comments on commit 2d97726

Please sign in to comment.