Git - experimental git blame editor decoration (#234209)

* Initial implementation

* Add setting, and cache blame information more aggressively
This commit is contained in:
Ladislau Szomoru
2024-11-19 22:05:19 +01:00
committed by GitHub
parent e7ee6c08df
commit 80635b487b
8 changed files with 531 additions and 4 deletions

View File

@@ -1054,6 +1054,76 @@ function parseGitChanges(repositoryRoot: string, raw: string): Change[] {
return result;
}
export interface BlameInformation {
readonly id: string;
readonly date?: number;
readonly message?: string;
readonly authorName?: string;
readonly authorEmail?: string;
readonly ranges: {
readonly startLineNumber: number;
readonly endLineNumber: number;
}[];
}
function parseGitBlame(data: string): BlameInformation[] {
const lineSeparator = /\r?\n/;
const commitRegex = /^([0-9a-f]{40})/gm;
const blameInformation = new Map<string, BlameInformation>();
let commitHash: string | undefined = undefined;
let authorName: string | undefined = undefined;
let authorEmail: string | undefined = undefined;
let authorTime: number | undefined = undefined;
let message: string | undefined = undefined;
let startLineNumber: number | undefined = undefined;
let endLineNumber: number | undefined = undefined;
for (const line of data.split(lineSeparator)) {
// Commit
const commitMatch = line.match(commitRegex);
if (!commitHash && commitMatch) {
const segments = line.split(' ');
commitHash = commitMatch[0];
startLineNumber = Number(segments[2]);
endLineNumber = Number(segments[2]) + Number(segments[3]) - 1;
}
// Commit properties
if (commitHash && line.startsWith('author ')) {
authorName = line.substring('author '.length);
}
if (commitHash && line.startsWith('author-mail ')) {
authorEmail = line.substring('author-mail '.length);
}
if (commitHash && line.startsWith('author-time ')) {
authorTime = Number(line.substring('author-time '.length)) * 1000;
}
if (commitHash && line.startsWith('summary ')) {
message = line.substring('summary '.length);
}
// Commit end
if (commitHash && startLineNumber && endLineNumber && line.startsWith('filename ')) {
const existingCommit = blameInformation.get(commitHash);
if (existingCommit) {
existingCommit.ranges.push({ startLineNumber, endLineNumber });
blameInformation.set(commitHash, existingCommit);
} else {
blameInformation.set(commitHash, {
id: commitHash, authorName, authorEmail, date: authorTime, message, ranges: [{ startLineNumber, endLineNumber }]
});
}
commitHash = authorName = authorEmail = authorTime = message = startLineNumber = endLineNumber = undefined;
}
}
return Array.from(blameInformation.values());
}
export interface PullOptions {
unshallow?: boolean;
tags?: boolean;
@@ -2137,6 +2207,18 @@ export class Repository {
}
}
async blame2(path: string): Promise<BlameInformation[] | undefined> {
try {
const args = ['blame', '--root', '--incremental', '--', sanitizePath(path)];
const result = await this.exec(args);
return parseGitBlame(result.stdout.trim());
}
catch (err) {
return undefined;
}
}
async createStash(message?: string, includeUntracked?: boolean, staged?: boolean): Promise<void> {
try {
const args = ['stash', 'push'];