Browse Source

Breaks `GitDiffParser` static class into functions

Changes `GitDiff` to `GitDiffFile` and adds new `GitDiff`
main
Eric Amodio 1 year ago
parent
commit
9928749b1e
9 changed files with 237 additions and 222 deletions
  1. +8
    -12
      src/ai/aiProviderService.ts
  2. +33
    -31
      src/env/node/git/localGitProvider.ts
  3. +4
    -4
      src/git/gitProvider.ts
  4. +4
    -4
      src/git/gitProviderService.ts
  5. +8
    -5
      src/git/models/diff.ts
  6. +173
    -159
      src/git/parsers/diffParser.ts
  7. +1
    -1
      src/hovers/hovers.ts
  8. +4
    -4
      src/plus/github/githubGitProvider.ts
  9. +2
    -2
      src/trackers/gitDocumentTracker.ts

+ 8
- 12
src/ai/aiProviderService.ts View File

@ -60,10 +60,8 @@ export class AIProviderService implements Disposable {
const repository = isRepository(repoOrPath) ? repoOrPath : this.container.git.getRepository(repoOrPath);
if (repository == null) throw new Error('Unable to find repository');
const diff = await this.container.git.getDiff(repository.uri, uncommittedStaged, undefined, {
includeRawDiff: true,
});
if (diff?.diff == null) throw new Error('No staged changes to generate a commit message from.');
const diff = await this.container.git.getDiff(repository.uri, uncommittedStaged);
if (diff == null) throw new Error('No staged changes to generate a commit message from.');
const provider = this.provider;
@ -72,10 +70,10 @@ export class AIProviderService implements Disposable {
if (options?.progress != null) {
return window.withProgress(options.progress, async () =>
provider.generateCommitMessage(diff.diff!, { context: options?.context }),
provider.generateCommitMessage(diff.contents, { context: options?.context }),
);
}
return provider.generateCommitMessage(diff.diff, { context: options?.context });
return provider.generateCommitMessage(diff.contents, { context: options?.context });
}
async explainCommit(
@ -107,10 +105,8 @@ export class AIProviderService implements Disposable {
}
if (commit == null) throw new Error('Unable to find commit');
const diff = await this.container.git.getDiff(commit.repoPath, commit.sha, undefined, {
includeRawDiff: true,
});
if (diff?.diff == null) throw new Error('No changes found to explain.');
const diff = await this.container.git.getDiff(commit.repoPath, commit.sha);
if (diff == null) throw new Error('No changes found to explain.');
const provider = this.provider;
@ -124,10 +120,10 @@ export class AIProviderService implements Disposable {
if (options?.progress != null) {
return window.withProgress(options.progress, async () =>
provider.explainChanges(commit!.message!, diff.diff!),
provider.explainChanges(commit!.message!, diff.contents),
);
}
return provider.explainChanges(commit.message, diff.diff);
return provider.explainChanges(commit.message, diff.contents);
}
}

+ 33
- 31
src/env/node/git/localGitProvider.ts View File

@ -64,7 +64,7 @@ import type { GitStashCommit } from '../../../git/models/commit';
import { GitCommit, GitCommitIdentity } from '../../../git/models/commit';
import { deletedOrMissing, uncommitted, uncommittedStaged } from '../../../git/models/constants';
import { GitContributor } from '../../../git/models/contributor';
import type { GitDiff, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from '../../../git/models/diff';
import type { GitDiff, GitDiffFile, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from '../../../git/models/diff';
import type { GitFile, GitFileStatus } from '../../../git/models/file';
import { GitFileChange } from '../../../git/models/file';
import type {
@ -110,7 +110,7 @@ import { isUserMatch } from '../../../git/models/user';
import type { GitWorktree } from '../../../git/models/worktree';
import { GitBlameParser } from '../../../git/parsers/blameParser';
import { GitBranchParser } from '../../../git/parsers/branchParser';
import { GitDiffParser } from '../../../git/parsers/diffParser';
import { parseDiffNameStatusFiles, parseDiffShortStat, parseFileDiff } from '../../../git/parsers/diffParser';
import {
createLogParserSingle,
createLogParserWithFiles,
@ -188,7 +188,7 @@ import { findGitPath, InvalidGitConfigError, UnableToFindGitError } from './loca
import { CancelledRunError, fsExists, RunError } from './shell';
const emptyArray = Object.freeze([]) as unknown as any[];
const emptyPromise: Promise<GitBlame | GitDiff | GitLog | undefined> = Promise.resolve(undefined);
const emptyPromise: Promise<GitBlame | GitDiffFile | GitLog | undefined> = Promise.resolve(undefined);
const emptyPagedResult: PagedResult<any> = Object.freeze({ values: [] });
const slash = 47;
@ -1837,7 +1837,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const data = await this.git.diff__shortstat(repoPath, ref);
if (!data) return undefined;
return GitDiffParser.parseShortStat(data);
return parseDiffShortStat(data);
}
@log()
@ -2615,35 +2615,37 @@ export class LocalGitProvider implements GitProvider, Disposable {
repoPath: string,
ref1: string,
ref2?: string,
options?: { includeRawDiff?: boolean },
options?: { context?: number },
): Promise<GitDiff | undefined> {
let data;
const params = [`-U${options?.context ?? 3}`];
if (ref1 === uncommitted) {
if (ref2 == null) {
data = await this.git.diff2(repoPath, undefined, '-U3');
} else {
data = await this.git.diff2(repoPath, undefined, '-U3', ref2);
if (ref2 != null) {
params.push(ref2);
}
} else if (ref1 === uncommittedStaged) {
if (ref2 == null) {
data = await this.git.diff2(repoPath, undefined, '-U3', '--staged');
} else {
data = await this.git.diff2(repoPath, undefined, '-U3', '--staged', ref2);
params.push('--staged');
if (ref2 != null) {
params.push(ref2);
}
} else if (ref2 == null) {
data = await this.git.diff2(repoPath, undefined, '-U3', `${ref1}^`, ref1);
if (ref1 === '' || ref1.toUpperCase() === 'HEAD') {
params.push('HEAD');
} else {
data = await this.git.diff2(repoPath, undefined, '-U3', ref1, ref2);
params.push(`${ref1}^`, ref1);
}
} else {
params.push(ref1, ref2);
}
const data = await this.git.diff2(repoPath, undefined, ...params);
if (!data) return undefined;
const diff = GitDiffParser.parse(data, options?.includeRawDiff);
const diff: GitDiff = { contents: data };
return diff;
}
@log()
async getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiff | undefined> {
async getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiffFile | undefined> {
const scope = getLogScope();
let key = 'diff';
@ -2687,7 +2689,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
Logger.debug(scope, `Cache add: '${key}'`);
const value: CachedDiff = {
item: promise as Promise<GitDiff>,
item: promise as Promise<GitDiffFile>,
};
doc.state.setDiff(key, value);
}
@ -2704,7 +2706,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
document: TrackedDocument<GitDocumentState>,
key: string,
scope: LogScope | undefined,
): Promise<GitDiff | undefined> {
): Promise<GitDiffFile | undefined> {
const [relativePath, root] = splitPath(path, repoPath);
try {
@ -2716,7 +2718,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
similarityThreshold: configuration.get('advanced.similarityThreshold'),
});
const diff = GitDiffParser.parse(data);
const diff = parseFileDiff(data);
return diff;
} catch (ex) {
// Trap and cache expected diff errors
@ -2725,12 +2727,12 @@ export class LocalGitProvider implements GitProvider, Disposable {
Logger.debug(scope, `Cache replace (with empty promise): '${key}'`);
const value: CachedDiff = {
item: emptyPromise as Promise<GitDiff>,
item: emptyPromise as Promise<GitDiffFile>,
errorMessage: msg,
};
document.state.setDiff(key, value);
return emptyPromise as Promise<GitDiff>;
return emptyPromise as Promise<GitDiffFile>;
}
return undefined;
@ -2738,7 +2740,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
@log<LocalGitProvider['getDiffForFileContents']>({ args: { 1: '<contents>' } })
async getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiff | undefined> {
async getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiffFile | undefined> {
const scope = getLogScope();
const key = `diff:${md5(contents)}`;
@ -2776,7 +2778,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
Logger.debug(scope, `Cache add: '${key}'`);
const value: CachedDiff = {
item: promise as Promise<GitDiff>,
item: promise as Promise<GitDiffFile>,
};
doc.state.setDiff(key, value);
}
@ -2793,7 +2795,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
document: TrackedDocument<GitDocumentState>,
key: string,
scope: LogScope | undefined,
): Promise<GitDiff | undefined> {
): Promise<GitDiffFile | undefined> {
const [relativePath, root] = splitPath(path, repoPath);
try {
@ -2803,7 +2805,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
similarityThreshold: configuration.get('advanced.similarityThreshold'),
});
const diff = GitDiffParser.parse(data);
const diff = parseFileDiff(data);
return diff;
} catch (ex) {
// Trap and cache expected diff errors
@ -2812,12 +2814,12 @@ export class LocalGitProvider implements GitProvider, Disposable {
Logger.debug(scope, `Cache replace (with empty promise): '${key}'`);
const value: CachedDiff = {
item: emptyPromise as Promise<GitDiff>,
item: emptyPromise as Promise<GitDiffFile>,
errorMessage: msg,
};
document.state.setDiff(key, value);
return emptyPromise as Promise<GitDiff>;
return emptyPromise as Promise<GitDiffFile>;
}
return undefined;
@ -2859,7 +2861,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
});
if (!data) return undefined;
const files = GitDiffParser.parseNameStatus(data, repoPath);
const files = parseDiffNameStatusFiles(data, repoPath);
return files == null || files.length === 0 ? undefined : files;
} catch (ex) {
return undefined;
@ -2875,7 +2877,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const data = await this.git.show__name_status(root, relativePath, ref);
if (!data) return undefined;
const files = GitDiffParser.parseNameStatus(data, repoPath);
const files = parseDiffNameStatusFiles(data, repoPath);
if (files == null || files.length === 0) return undefined;
return files[0];

+ 4
- 4
src/git/gitProvider.ts View File

@ -7,7 +7,7 @@ import type { GitBlame, GitBlameLine, GitBlameLines } from './models/blame';
import type { BranchSortOptions, GitBranch } from './models/branch';
import type { GitCommit } from './models/commit';
import type { GitContributor } from './models/contributor';
import type { GitDiff, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from './models/diff';
import type { GitDiff, GitDiffFile, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from './models/diff';
import type { GitFile } from './models/file';
import type { GitGraph } from './models/graph';
import type { GitLog } from './models/log';
@ -275,7 +275,7 @@ export interface GitProvider extends Disposable {
repoPath: string | Uri,
ref1: string,
ref2?: string,
options?: { includeRawDiff?: boolean },
options?: { context?: number },
): Promise<GitDiff | undefined>;
/**
* Returns a file diff between two commits
@ -283,14 +283,14 @@ export interface GitProvider extends Disposable {
* @param ref1 Commit to diff from
* @param ref2 Commit to diff to
*/
getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiff | undefined>;
getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiffFile | undefined>;
/**
* Returns a file diff between a commit and the specified contents
* @param uri Uri of the file to diff
* @param ref Commit to diff from
* @param contents Contents to use for the diff
*/
getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiff | undefined>;
getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiffFile | undefined>;
/**
* Returns a line diff between two commits
* @param uri Uri of the file to diff

+ 4
- 4
src/git/gitProviderService.ts View File

@ -56,7 +56,7 @@ import type { BranchSortOptions, GitBranch } from './models/branch';
import { GitCommit, GitCommitIdentity } from './models/commit';
import { deletedOrMissing, uncommitted, uncommittedStaged } from './models/constants';
import type { GitContributor } from './models/contributor';
import type { GitDiff, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from './models/diff';
import type { GitDiff, GitDiffFile, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from './models/diff';
import type { GitFile } from './models/file';
import type { GitGraph } from './models/graph';
import type { SearchedIssue } from './models/issue';
@ -1706,7 +1706,7 @@ export class GitProviderService implements Disposable {
repoPath: string | Uri,
ref1: string,
ref2?: string,
options?: { includeRawDiff?: boolean },
options?: { context?: number },
): Promise<GitDiff | undefined> {
const { provider, path } = this.getProvider(repoPath);
return provider.getDiff?.(path, ref1, ref2, options);
@ -1719,7 +1719,7 @@ export class GitProviderService implements Disposable {
* @param ref1 Commit to diff from
* @param ref2 Commit to diff to
*/
getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiff | undefined> {
getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiffFile | undefined> {
const { provider } = this.getProvider(uri);
return provider.getDiffForFile(uri, ref1, ref2);
}
@ -1731,7 +1731,7 @@ export class GitProviderService implements Disposable {
* @param ref Commit to diff from
* @param contents Contents to use for the diff
*/
getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiff | undefined> {
getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise<GitDiffFile | undefined> {
const { provider } = this.getProvider(uri);
return provider.getDiffForFileContents(uri, ref, contents);
}

+ 8
- 5
src/git/models/diff.ts View File

@ -1,4 +1,4 @@
import { GitDiffParser } from '../parsers/diffParser';
import { parseDiffHunk } from '../parsers/diffParser';
export interface GitDiffLine {
line: string;
@ -13,7 +13,7 @@ export interface GitDiffHunkLine {
export class GitDiffHunk {
constructor(
public readonly diff: string,
public readonly contents: string,
public current: {
count: number;
position: { start: number; end: number };
@ -35,16 +35,19 @@ export class GitDiffHunk {
private parsedHunk: { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } | undefined;
private parseHunk() {
if (this.parsedHunk == null) {
this.parsedHunk = GitDiffParser.parseHunk(this);
this.parsedHunk = parseDiffHunk(this);
}
return this.parsedHunk;
}
}
export interface GitDiff {
readonly hunks: GitDiffHunk[];
readonly contents: string;
}
readonly diff?: string;
export interface GitDiffFile {
readonly hunks: GitDiffHunk[];
readonly contents?: string;
}
export interface GitDiffShortStat {

+ 173
- 159
src/git/parsers/diffParser.ts View File

@ -1,190 +1,204 @@
import { debug } from '../../system/decorators/log';
import { getLines } from '../../system/string';
import type { GitDiff, GitDiffHunkLine, GitDiffLine, GitDiffShortStat } from '../models/diff';
import { LogLevel } from '../../system/logger.constants';
import { maybeStopWatch } from '../../system/stopwatch';
import { getLines, pluralize } from '../../system/string';
import type { GitDiffFile, GitDiffHunkLine, GitDiffLine, GitDiffShortStat } from '../models/diff';
import { GitDiffHunk } from '../models/diff';
import type { GitFile, GitFileStatus } from '../models/file';
const shortStatDiffRegex = /(\d+)\s+files? changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/;
const unifiedDiffRegex = /^@@ -([\d]+)(?:,([\d]+))? \+([\d]+)(?:,([\d]+))? @@(?:.*?)\n([\s\S]*?)(?=^@@)/gm;
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class GitDiffParser {
@debug({ args: false, singleLine: true })
static parse(data: string, includeRawDiff: boolean = false): GitDiff | undefined {
if (!data) return undefined;
const hunks: GitDiffHunk[] = [];
let previousStart;
let previousCount;
let currentStart;
let currentCount;
let hunk;
let match;
do {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match == null) break;
[, previousStart, previousCount, currentStart, currentCount, hunk] = match;
previousCount = Number(previousCount) || 0;
previousStart = Number(previousStart) || 0;
currentCount = Number(currentCount) || 0;
currentStart = Number(currentStart) || 0;
hunks.push(
new GitDiffHunk(
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
` ${hunk}`.substr(1),
{
count: currentCount === 0 ? 1 : currentCount,
position: {
start: currentStart,
end: currentStart + (currentCount > 0 ? currentCount - 1 : 0),
},
export function parseFileDiff(data: string, includeContents: boolean = false): GitDiffFile | undefined {
if (!data) return undefined;
const sw = maybeStopWatch('parseFileDiff', { log: false, logLevel: LogLevel.Debug });
const hunks: GitDiffHunk[] = [];
let previousStart;
let previousCount;
let currentStart;
let currentCount;
let hunk;
let match;
do {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match == null) break;
[, previousStart, previousCount, currentStart, currentCount, hunk] = match;
previousCount = Number(previousCount) || 0;
previousStart = Number(previousStart) || 0;
currentCount = Number(currentCount) || 0;
currentStart = Number(currentStart) || 0;
hunks.push(
new GitDiffHunk(
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
` ${hunk}`.substr(1),
{
count: currentCount === 0 ? 1 : currentCount,
position: {
start: currentStart,
end: currentStart + (currentCount > 0 ? currentCount - 1 : 0),
},
{
count: previousCount === 0 ? 1 : previousCount,
position: {
start: previousStart,
end: previousStart + (previousCount > 0 ? previousCount - 1 : 0),
},
},
{
count: previousCount === 0 ? 1 : previousCount,
position: {
start: previousStart,
end: previousStart + (previousCount > 0 ? previousCount - 1 : 0),
},
),
);
} while (true);
},
),
);
} while (true);
if (!hunks.length) return undefined;
sw?.stop({ suffix: ` parsed ${pluralize('hunk', hunks.length)}` });
const diff: GitDiff = {
diff: includeRawDiff ? data : undefined,
hunks: hunks,
};
return diff;
}
if (!hunks.length) return undefined;
@debug({ args: false, singleLine: true })
static parseHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } {
const currentStart = hunk.current.position.start;
const previousStart = hunk.previous.position.start;
const currentLines: (GitDiffLine | undefined)[] =
currentStart > previousStart
? new Array(currentStart - previousStart).fill(undefined, 0, currentStart - previousStart)
: [];
const previousLines: (GitDiffLine | undefined)[] =
previousStart > currentStart
? new Array(previousStart - currentStart).fill(undefined, 0, previousStart - currentStart)
: [];
let hasAddedOrChanged;
let hasRemoved;
let removed = 0;
for (const l of getLines(hunk.diff)) {
switch (l[0]) {
case '+':
hasAddedOrChanged = true;
currentLines.push({
line: ` ${l.substring(1)}`,
state: 'added',
});
if (removed > 0) {
removed--;
} else {
previousLines.push(undefined);
}
break;
case '-':
hasRemoved = true;
removed++;
previousLines.push({
line: ` ${l.substring(1)}`,
state: 'removed',
});
break;
default:
while (removed > 0) {
removed--;
currentLines.push(undefined);
}
currentLines.push({ line: l, state: 'unchanged' });
previousLines.push({ line: l, state: 'unchanged' });
break;
}
}
const diff: GitDiffFile = {
contents: includeContents ? data : undefined,
hunks: hunks,
};
return diff;
}
while (removed > 0) {
removed--;
currentLines.push(undefined);
export function parseDiffHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } {
const sw = maybeStopWatch('parseDiffHunk', { log: false, logLevel: LogLevel.Debug });
const currentStart = hunk.current.position.start;
const previousStart = hunk.previous.position.start;
const currentLines: (GitDiffLine | undefined)[] =
currentStart > previousStart
? new Array(currentStart - previousStart).fill(undefined, 0, currentStart - previousStart)
: [];
const previousLines: (GitDiffLine | undefined)[] =
previousStart > currentStart
? new Array(previousStart - currentStart).fill(undefined, 0, previousStart - currentStart)
: [];
let hasAddedOrChanged;
let hasRemoved;
let removed = 0;
for (const l of getLines(hunk.contents)) {
switch (l[0]) {
case '+':
hasAddedOrChanged = true;
currentLines.push({
line: ` ${l.substring(1)}`,
state: 'added',
});
if (removed > 0) {
removed--;
} else {
previousLines.push(undefined);
}
break;
case '-':
hasRemoved = true;
removed++;
previousLines.push({
line: ` ${l.substring(1)}`,
state: 'removed',
});
break;
default:
while (removed > 0) {
removed--;
currentLines.push(undefined);
}
currentLines.push({ line: l, state: 'unchanged' });
previousLines.push({ line: l, state: 'unchanged' });
break;
}
}
const hunkLines: GitDiffHunkLine[] = [];
while (removed > 0) {
removed--;
currentLines.push(undefined);
}
for (let i = 0; i < Math.max(currentLines.length, previousLines.length); i++) {
hunkLines.push({
hunk: hunk,
current: currentLines[i],
previous: previousLines[i],
});
}
const hunkLines: GitDiffHunkLine[] = [];
return {
lines: hunkLines,
state: hasAddedOrChanged && hasRemoved ? 'changed' : hasAddedOrChanged ? 'added' : 'removed',
};
for (let i = 0; i < Math.max(currentLines.length, previousLines.length); i++) {
hunkLines.push({
hunk: hunk,
current: currentLines[i],
previous: previousLines[i],
});
}
@debug({ args: false, singleLine: true })
static parseNameStatus(data: string, repoPath: string): GitFile[] | undefined {
if (!data) return undefined;
sw?.stop({ suffix: ` parsed ${pluralize('line', hunkLines.length)}` });
return {
lines: hunkLines,
state: hasAddedOrChanged && hasRemoved ? 'changed' : hasAddedOrChanged ? 'added' : 'removed',
};
}
export function parseDiffNameStatusFiles(data: string, repoPath: string): GitFile[] | undefined {
if (!data) return undefined;
const files: GitFile[] = [];
const sw = maybeStopWatch('parseDiffNameStatusFiles', { log: false, logLevel: LogLevel.Debug });
let status;
const files: GitFile[] = [];
const fields = data.split('\0');
for (let i = 0; i < fields.length - 1; i++) {
status = fields[i][0];
if (status === '.') {
status = '?';
}
let status;
files.push({
status: status as GitFileStatus,
path: fields[++i],
originalPath: status.startsWith('R') || status.startsWith('C') ? fields[++i] : undefined,
repoPath: repoPath,
});
const fields = data.split('\0');
for (let i = 0; i < fields.length - 1; i++) {
status = fields[i][0];
if (status === '.') {
status = '?';
}
return files;
files.push({
status: status as GitFileStatus,
path: fields[++i],
originalPath: status.startsWith('R') || status.startsWith('C') ? fields[++i] : undefined,
repoPath: repoPath,
});
}
@debug({ args: false, singleLine: true })
static parseShortStat(data: string): GitDiffShortStat | undefined {
if (!data) return undefined;
sw?.stop({ suffix: ` parsed ${pluralize('file', files.length)}` });
const match = shortStatDiffRegex.exec(data);
if (match == null) return undefined;
return files;
}
const [, files, insertions, deletions] = match;
export function parseDiffShortStat(data: string): GitDiffShortStat | undefined {
if (!data) return undefined;
const diffShortStat: GitDiffShortStat = {
changedFiles: files == null ? 0 : parseInt(files, 10),
additions: insertions == null ? 0 : parseInt(insertions, 10),
deletions: deletions == null ? 0 : parseInt(deletions, 10),
};
const sw = maybeStopWatch('parseDiffShortStat', { log: false, logLevel: LogLevel.Debug });
return diffShortStat;
}
const match = shortStatDiffRegex.exec(data);
if (match == null) return undefined;
const [, files, insertions, deletions] = match;
const diffShortStat: GitDiffShortStat = {
changedFiles: files == null ? 0 : parseInt(files, 10),
additions: insertions == null ? 0 : parseInt(insertions, 10),
deletions: deletions == null ? 0 : parseInt(deletions, 10),
};
sw?.stop({
suffix: ` parsed ${pluralize('file', diffShortStat.changedFiles)}, +${diffShortStat.additions} -${
diffShortStat.deletions
}`,
});
return diffShortStat;
}

+ 1
- 1
src/hovers/hovers.ts View File

@ -273,7 +273,7 @@ export async function detailsMessage(
}
function getDiffFromHunk(hunk: GitDiffHunk): string {
return `\`\`\`diff\n${hunk.diff.trim()}\n\`\`\``;
return `\`\`\`diff\n${hunk.contents.trim()}\n\`\`\``;
}
function getDiffFromHunkLine(hunkLine: GitDiffHunkLine, diffStyle?: 'line' | 'hunk'): string {

+ 4
- 4
src/plus/github/githubGitProvider.ts View File

@ -43,7 +43,7 @@ import type { GitCommitLine } from '../../git/models/commit';
import { getChangedFilesCount, GitCommit, GitCommitIdentity } from '../../git/models/commit';
import { deletedOrMissing, uncommitted } from '../../git/models/constants';
import { GitContributor } from '../../git/models/contributor';
import type { GitDiff, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from '../../git/models/diff';
import type { GitDiffFile, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from '../../git/models/diff';
import type { GitFile } from '../../git/models/file';
import { GitFileChange, GitFileIndexStatus } from '../../git/models/file';
import type {
@ -105,7 +105,7 @@ import { fromCommitFileStatus } from './models';
const doubleQuoteRegex = /"/g;
const emptyArray = Object.freeze([]) as unknown as any[];
const emptyPagedResult: PagedResult<any> = Object.freeze({ values: [] });
const emptyPromise: Promise<GitBlame | GitDiff | GitLog | undefined> = Promise.resolve(undefined);
const emptyPromise: Promise<GitBlame | GitDiffFile | GitLog | undefined> = Promise.resolve(undefined);
const githubAuthenticationScopes = ['repo', 'read:user', 'user:email'];
@ -1665,7 +1665,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
}
@log()
async getDiffForFile(_uri: GitUri, _ref1: string | undefined, _ref2?: string): Promise<GitDiff | undefined> {
async getDiffForFile(_uri: GitUri, _ref1: string | undefined, _ref2?: string): Promise<GitDiffFile | undefined> {
return undefined;
}
@ -1674,7 +1674,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
1: _contents => '<contents>',
},
})
async getDiffForFileContents(_uri: GitUri, _ref: string, _contents: string): Promise<GitDiff | undefined> {
async getDiffForFileContents(_uri: GitUri, _ref: string, _contents: string): Promise<GitDiffFile | undefined> {
return undefined;
}

+ 2
- 2
src/trackers/gitDocumentTracker.ts View File

@ -1,6 +1,6 @@
import type { TextDocument, Uri } from 'vscode';
import type { GitBlame } from '../git/models/blame';
import type { GitDiff } from '../git/models/diff';
import type { GitDiffFile } from '../git/models/diff';
import type { GitLog } from '../git/models/log';
import { DocumentTracker } from './documentTracker';
@ -12,7 +12,7 @@ interface CachedItem {
}
export type CachedBlame = CachedItem<GitBlame>;
export type CachedDiff = CachedItem<GitDiff>;
export type CachedDiff = CachedItem<GitDiffFile>;
export type CachedLog = CachedItem<GitLog>;
export class GitDocumentState {

Loading…
Cancel
Save