Adds timeline diff on click and icon support

This commit is contained in:
Eric Amodio
2020-01-17 17:19:52 -05:00
committed by Eric Amodio
parent 70e1e9b4f4
commit 87c2332fed
17 changed files with 424 additions and 248 deletions

View File

@@ -12,10 +12,10 @@ import { EventEmitter } from 'events';
import iconv = require('iconv-lite');
import * as filetype from 'file-type';
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
import { CancellationToken, Progress } from 'vscode';
import { CancellationToken, Progress, Uri } from 'vscode';
import { URI } from 'vscode-uri';
import { detectEncoding } from './encoding';
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git';
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, LogFileOptions } from './api/git';
import * as byline from 'byline';
import { StringDecoder } from 'string_decoder';
@@ -318,7 +318,7 @@ function getGitErrorCode(stderr: string): string | undefined {
return undefined;
}
const COMMIT_FORMAT = '%H\n%ae\n%P\n%B';
const COMMIT_FORMAT = '%H\n%aN\n%aE\n%at\n%P\n%B';
export class Git {
@@ -503,7 +503,9 @@ export interface Commit {
hash: string;
message: string;
parents: string[];
authorEmail?: string | undefined;
authorDate?: Date;
authorName?: string;
authorEmail?: string;
}
export class GitStatusParser {
@@ -634,14 +636,43 @@ export function parseGitmodules(raw: string): Submodule[] {
return result;
}
export function parseGitCommit(raw: string): Commit | null {
const match = /^([0-9a-f]{40})\n(.*)\n(.*)(\n([^]*))?$/m.exec(raw.trim());
if (!match) {
return null;
}
const commitRegex = /([0-9a-f]{40})\n(.*)\n(.*)\n(.*)\n(.*)(?:\n([^]*?))?(?:\x00)/gm;
const parents = match[3] ? match[3].split(' ') : [];
return { hash: match[1], message: match[5], parents, authorEmail: match[2] };
export function parseGitCommits(data: string): Commit[] {
let commits: Commit[] = [];
let ref;
let name;
let email;
let date;
let parents;
let message;
let match;
do {
match = commitRegex.exec(data);
if (match === null) {
break;
}
[, ref, name, email, date, parents, message] = match;
if (message[message.length - 1] === '\n') {
message = message.substr(0, message.length - 1);
}
// Stop excessive memory usage by using substr -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
commits.push({
hash: ` ${ref}`.substr(1),
message: ` ${message}`.substr(1),
parents: parents ? parents.split(' ') : [],
authorDate: new Date(Number(date) * 1000),
authorName: ` ${name}`.substr(1),
authorEmail: ` ${email}`.substr(1)
});
} while (true);
return commits;
}
interface LsTreeElement {
@@ -760,38 +791,28 @@ export class Repository {
async log(options?: LogOptions): Promise<Commit[]> {
const maxEntries = options && typeof options.maxEntries === 'number' && options.maxEntries > 0 ? options.maxEntries : 32;
const args = ['log', '-' + maxEntries, `--pretty=format:${COMMIT_FORMAT}%x00%x00`];
const args = ['log', '-' + maxEntries, `--format:${COMMIT_FORMAT}`, '-z'];
const gitResult = await this.run(args);
if (gitResult.exitCode) {
const result = await this.run(args);
if (result.exitCode) {
// An empty repo
return [];
}
const s = gitResult.stdout;
const result: Commit[] = [];
let index = 0;
while (index < s.length) {
let nextIndex = s.indexOf('\x00\x00', index);
if (nextIndex === -1) {
nextIndex = s.length;
}
return parseGitCommits(result.stdout);
}
let entry = s.substr(index, nextIndex - index);
if (entry.startsWith('\n')) {
entry = entry.substring(1);
}
async logFile(uri: Uri, options?: LogFileOptions): Promise<Commit[]> {
const maxEntries = options?.maxEntries ?? 32;
const args = ['log', `-${maxEntries}`, `--format=${COMMIT_FORMAT}`, '-z', '--', uri.fsPath];
const commit = parseGitCommit(entry);
if (!commit) {
break;
}
result.push(commit);
index = nextIndex + 2;
const result = await this.run(args);
if (result.exitCode) {
// No file history, e.g. a new file or untracked
return [];
}
return result;
return parseGitCommits(result.stdout);
}
async bufferString(object: string, encoding: string = 'utf8', autoGuessEncoding = false): Promise<string> {
@@ -1853,8 +1874,12 @@ export class Repository {
}
async getCommit(ref: string): Promise<Commit> {
const result = await this.run(['show', '-s', `--format=${COMMIT_FORMAT}`, ref]);
return parseGitCommit(result.stdout) || Promise.reject<Commit>('bad commit format');
const result = await this.run(['show', '-s', `--format=${COMMIT_FORMAT}`, '-z', ref]);
const commits = parseGitCommits(result.stdout);
if (commits.length === 0) {
return Promise.reject<Commit>('bad commit format');
}
return commits[0];
}
async updateSubmodules(paths: string[]): Promise<void> {