Quellcode durchsuchen

Attempts to consolidate commit models (wip)

First pass at converting "blame" commits into a unified model
main
Eric Amodio vor 2 Jahren
Ursprung
Commit
4979fb1e39
42 geänderte Dateien mit 847 neuen und 474 gelöschten Zeilen
  1. +3
    -3
      src/annotations/annotations.ts
  2. +15
    -15
      src/annotations/blameAnnotationProvider.ts
  3. +6
    -6
      src/annotations/gutterBlameAnnotationProvider.ts
  4. +2
    -2
      src/annotations/gutterHeatmapBlameAnnotationProvider.ts
  5. +3
    -3
      src/annotations/lineAnnotationController.ts
  6. +1
    -1
      src/avatars.ts
  7. +13
    -13
      src/codelens/codeLensProvider.ts
  8. +3
    -2
      src/commands/common.ts
  9. +27
    -15
      src/commands/diffLineWithWorking.ts
  10. +12
    -7
      src/commands/diffWith.ts
  11. +3
    -3
      src/commands/diffWithPrevious.ts
  12. +5
    -12
      src/commands/openCommitOnRemote.ts
  13. +4
    -4
      src/commands/showQuickCommit.ts
  14. +22
    -16
      src/commands/showQuickCommitFile.ts
  15. +13
    -13
      src/env/node/git/localGitProvider.ts
  16. +72
    -59
      src/git/formatters/commitFormatter.ts
  17. +6
    -0
      src/git/gitProviderService.ts
  18. +2
    -2
      src/git/gitUri.ts
  19. +0
    -1
      src/git/models.ts
  20. +4
    -5
      src/git/models/blame.ts
  21. +0
    -64
      src/git/models/blameCommit.ts
  22. +312
    -4
      src/git/models/commit.ts
  23. +1
    -1
      src/git/models/file.ts
  24. +24
    -6
      src/git/models/logCommit.ts
  25. +77
    -38
      src/git/parsers/blameParser.ts
  26. +1
    -1
      src/git/parsers/diffParser.ts
  27. +4
    -3
      src/git/parsers/logParser.ts
  28. +1
    -1
      src/git/parsers/stashParser.ts
  29. +41
    -34
      src/hovers/hovers.ts
  30. +17
    -17
      src/hovers/lineHoverController.ts
  31. +5
    -3
      src/messages.ts
  32. +42
    -26
      src/premium/github/github.ts
  33. +27
    -25
      src/premium/github/githubGitProvider.ts
  34. +2
    -2
      src/quickpicks/gitQuickPickItems.ts
  35. +5
    -5
      src/statusbar/statusBarController.ts
  36. +13
    -13
      src/system/string.ts
  37. +2
    -2
      src/trackers/gitLineTracker.ts
  38. +2
    -2
      src/views/nodes/commitFileNode.ts
  39. +2
    -2
      src/views/nodes/fileRevisionAsCommitNode.ts
  40. +23
    -23
      src/views/nodes/lineHistoryNode.ts
  41. +12
    -10
      src/webviews/rebaseEditor.ts
  42. +18
    -10
      src/webviews/webviewBase.ts

+ 3
- 3
src/annotations/annotations.ts Datei anzeigen

@ -15,7 +15,7 @@ import { Config, configuration } from '../configuration';
import { Colors, GlyphChars } from '../constants';
import { Container } from '../container';
import { CommitFormatOptions, CommitFormatter } from '../git/formatters';
import { GitCommit } from '../git/models';
import { GitCommit2 } from '../git/models';
import { Strings } from '../system';
import { toRgba } from '../webviews/apps/shared/colors';
@ -141,7 +141,7 @@ export class Annotations {
}
static gutter(
commit: GitCommit,
commit: GitCommit2,
format: string,
dateFormatOrFormatOptions: string | null | CommitFormatOptions,
renderOptions: RenderOptions,
@ -227,7 +227,7 @@ export class Annotations {
}
static trailing(
commit: GitCommit,
commit: GitCommit2,
// uri: GitUri,
// editorLine: number,
format: string,

+ 15
- 15
src/annotations/blameAnnotationProvider.ts Datei anzeigen

@ -2,7 +2,7 @@ import { CancellationToken, Disposable, Hover, languages, Position, Range, TextD
import { FileAnnotationType } from '../config';
import { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitBlame, GitBlameCommit, GitCommit } from '../git/models';
import { GitBlame, GitCommit2 } from '../git/models';
import { Hovers } from '../hovers/hovers';
import { log } from '../system';
import { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker';
@ -171,19 +171,19 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
);
}
private async getDetailsHoverMessage(commit: GitBlameCommit, document: TextDocument) {
// Get the full commit message -- since blame only returns the summary
let logCommit: GitCommit | undefined = undefined;
if (!commit.isUncommitted) {
logCommit = await this.container.git.getCommitForFile(commit.repoPath, commit.uri, {
ref: commit.sha,
});
if (logCommit != null) {
// Preserve the previous commit from the blame commit
logCommit.previousFileName = commit.previousFileName;
logCommit.previousSha = commit.previousSha;
}
}
private async getDetailsHoverMessage(commit: GitCommit2, document: TextDocument) {
// // Get the full commit message -- since blame only returns the summary
// let logCommit: GitCommit | undefined = undefined;
// if (!commit.isUncommitted) {
// logCommit = await this.container.git.getCommitForFile(commit.repoPath, commit.uri, {
// ref: commit.sha,
// });
// if (logCommit != null) {
// // Preserve the previous commit from the blame commit
// logCommit.previousFileName = commit.previousFileName;
// logCommit.previousSha = commit.previousSha;
// }
// }
let editorLine = this.editor.selection.active.line;
const line = editorLine + 1;
@ -191,7 +191,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
editorLine = commitLine.originalLine - 1;
return Hovers.detailsMessage(
logCommit ?? commit,
commit,
await GitUri.fromUri(document.uri),
editorLine,
this.container.config.hovers.detailsMarkdownFormat,

+ 6
- 6
src/annotations/gutterBlameAnnotationProvider.ts Datei anzeigen

@ -3,7 +3,7 @@ import { FileAnnotationType, GravatarDefaultStyle } from '../configuration';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { CommitFormatOptions, CommitFormatter } from '../git/formatters';
import { GitBlame, GitBlameCommit } from '../git/models';
import { GitBlame, GitCommit2 } from '../git/models';
import { Logger } from '../logger';
import { Arrays, Iterables, log, Stopwatch, Strings } from '../system';
import { GitDocumentState } from '../trackers/gitDocumentTracker';
@ -75,7 +75,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
const decorationsMap = new Map<string, DecorationOptions | undefined>();
const avatarDecorationsMap = avatars ? new Map<string, ThemableDecorationAttachmentRenderOptions>() : undefined;
let commit: GitBlameCommit | undefined;
let commit: GitCommit2 | undefined;
let compacted = false;
let gutter: DecorationOptions | undefined;
let previousSha: string | undefined;
@ -150,7 +150,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
decorationOptions.push(gutter);
if (avatars && commit.email != null) {
if (avatars && commit.author.email != null) {
await this.applyAvatarDecoration(commit, gutter, gravatarDefault, avatarDecorationsMap!);
}
@ -208,12 +208,12 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
}
private async applyAvatarDecoration(
commit: GitBlameCommit,
commit: GitCommit2,
gutter: DecorationOptions,
gravatarDefault: GravatarDefaultStyle,
map: Map<string, ThemableDecorationAttachmentRenderOptions>,
) {
let avatarDecoration = map.get(commit.email!);
let avatarDecoration = map.get(commit.author.email ?? '');
if (avatarDecoration == null) {
const url = (await commit.getAvatarUri({ defaultStyle: gravatarDefault, size: 16 })).toString(true);
avatarDecoration = {
@ -224,7 +224,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
url,
)});background-size:16px 16px;margin-left: 0 !important`,
};
map.set(commit.email!, avatarDecoration);
map.set(commit.author.email ?? '', avatarDecoration);
}
gutter.renderOptions!.after = avatarDecoration;

+ 2
- 2
src/annotations/gutterHeatmapBlameAnnotationProvider.ts Datei anzeigen

@ -1,7 +1,7 @@
import { Range, TextEditor, TextEditorDecorationType } from 'vscode';
import { FileAnnotationType } from '../configuration';
import { Container } from '../container';
import { GitBlameCommit } from '../git/models';
import { GitCommit2 } from '../git/models';
import { Logger } from '../logger';
import { log, Stopwatch } from '../system';
import { GitDocumentState } from '../trackers/gitDocumentTracker';
@ -32,7 +32,7 @@ export class GutterHeatmapBlameAnnotationProvider extends BlameAnnotationProvide
>();
const computedHeatmap = await this.getComputedHeatmap(blame);
let commit: GitBlameCommit | undefined;
let commit: GitCommit2 | undefined;
for (const l of blame.lines) {
// editor lines are 0-based
const editorLine = l.line - 1;

+ 3
- 3
src/annotations/lineAnnotationController.ts Datei anzeigen

@ -14,7 +14,7 @@ import { configuration } from '../configuration';
import { GlyphChars, isTextEditor } from '../constants';
import { Container } from '../container';
import { CommitFormatter } from '../git/formatters';
import { GitBlameCommit, PullRequest } from '../git/models';
import { GitCommit2, PullRequest } from '../git/models';
import { Authentication } from '../git/remotes/provider';
import { LogCorrelationContext, Logger } from '../logger';
import { debug, log } from '../system/decorators/log';
@ -155,7 +155,7 @@ export class LineAnnotationController implements Disposable {
private async getPullRequests(
repoPath: string,
lines: [number, GitBlameCommit][],
lines: [number, GitCommit2][],
{ timeout }: { timeout?: number } = {},
) {
if (lines.length === 0) return undefined;
@ -250,7 +250,7 @@ export class LineAnnotationController implements Disposable {
}
const commitLines = [
...filterMap<LineSelection, [number, GitBlameCommit]>(selections, selection => {
...filterMap<LineSelection, [number, GitCommit2]>(selections, selection => {
const state = this.container.lineTracker.getState(selection.active);
if (state?.commit == null) {
Logger.debug(cc, `Line ${selection.active} returned no commit`);

+ 1
- 1
src/avatars.ts Datei anzeigen

@ -78,7 +78,7 @@ export function getAvatarUri(
// Double the size to avoid blurring on the retina screen
size *= 2;
if (email == null || email.length === 0) {
if (!email) {
const avatar = createOrUpdateAvatar(
`${missingGravatarHash}:${size}`,
undefined,

+ 13
- 13
src/codelens/codeLensProvider.ts Datei anzeigen

@ -38,7 +38,7 @@ import {
import { BuiltInCommands, DocumentSchemes } from '../constants';
import { Container } from '../container';
import type { GitUri } from '../git/gitUri';
import { GitBlame, GitBlameLines, GitCommit } from '../git/models';
import { GitBlame, GitBlameLines, GitCommit2 } from '../git/models';
import { RemoteResourceType } from '../git/remotes/provider';
import { Logger } from '../logger';
import { is, once } from '../system/function';
@ -488,7 +488,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
const blame = lens.getBlame();
if (blame === undefined) return lens;
const recentCommit: GitCommit = first(blame.commits.values());
const recentCommit = first(blame.commits.values());
// TODO@eamodio This is FAR too expensive, but this accounts for commits that delete lines -- is there another way?
// if (lens.uri != null) {
// const commit = await this.container.git.getCommitForFile(lens.uri.repoPath, lens.uri.fsPath, {
@ -503,7 +503,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
// }
// }
let title = `${recentCommit.author}, ${
let title = `${recentCommit.author.name}, ${
lens.dateFormat == null ? recentCommit.formattedDate : recentCommit.formatDate(lens.dateFormat)
}`;
if (this.container.config.debug) {
@ -594,7 +594,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
return this.applyCommandWithNoClickAction(title, lens);
}
const commit = find(blame.commits.values(), c => c.author === author) ?? first(blame.commits.values());
const commit = find(blame.commits.values(), c => c.author.name === author) ?? first(blame.commits.values());
switch (lens.desiredCommand) {
case CodeLensCommand.CopyRemoteCommitUrl:
@ -635,7 +635,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyDiffWithPreviousCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit | undefined,
commit: GitCommit2 | undefined,
): T {
lens.command = command<[undefined, DiffWithPreviousCommandArgs]>({
title: title,
@ -654,7 +654,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyCopyOrOpenCommitOnRemoteCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit,
commit: GitCommit2,
clipboard: boolean = false,
): T {
lens.command = command<[OpenOnRemoteCommandArgs]>({
@ -677,7 +677,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyCopyOrOpenFileOnRemoteCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit,
commit: GitCommit2,
clipboard: boolean = false,
): T {
lens.command = command<[OpenOnRemoteCommandArgs]>({
@ -687,7 +687,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
{
resource: {
type: RemoteResourceType.Revision,
fileName: commit.fileName,
fileName: commit.file?.path ?? '',
sha: commit.sha,
},
repoPath: commit.repoPath,
@ -701,7 +701,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyRevealCommitInViewCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit | undefined,
commit: GitCommit2 | undefined,
): T {
lens.command = command<[Uri, ShowQuickCommitCommandArgs]>({
title: title,
@ -721,7 +721,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
title: string,
lens: T,
blame: GitBlameLines,
commit?: GitCommit,
commit?: GitCommit2,
): T {
let refs;
if (commit === undefined) {
@ -746,7 +746,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyShowQuickCommitDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit | undefined,
commit: GitCommit2 | undefined,
): T {
lens.command = command<[Uri, ShowQuickCommitCommandArgs]>({
title: title,
@ -765,7 +765,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyShowQuickCommitFileDetailsCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit | undefined,
commit: GitCommit2 | undefined,
): T {
lens.command = command<[Uri, ShowQuickCommitFileCommandArgs]>({
title: title,
@ -825,7 +825,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
private applyToggleFileChangesCommand<T extends GitRecentChangeCodeLens | GitAuthorsCodeLens>(
title: string,
lens: T,
commit: GitCommit,
commit: GitCommit2,
only?: boolean,
): T {
lens.command = command<[Uri, ToggleFileChangesAnnotationCommandArgs]>({

+ 3
- 2
src/commands/common.ts Datei anzeigen

@ -20,6 +20,7 @@ import { GitUri } from '../git/gitUri';
import {
GitBranch,
GitCommit,
GitCommit2,
GitContributor,
GitFile,
GitReference,
@ -324,12 +325,12 @@ export function isCommandContextViewNodeHasBranch(
return GitBranch.is((context.node as ViewNode & { branch: GitBranch }).branch);
}
export function isCommandContextViewNodeHasCommit<T extends GitCommit>(
export function isCommandContextViewNodeHasCommit<T extends GitCommit | GitCommit2>(
context: CommandContext,
): context is CommandViewNodeContext & { node: ViewNode & { commit: T } } {
if (context.type !== 'viewItem') return false;
return GitCommit.is((context.node as ViewNode & { commit: GitCommit }).commit);
return GitCommit.is((context.node as ViewNode & { commit: GitCommit | GitCommit2 }).commit);
}
export function isCommandContextViewNodeHasContributor(

+ 27
- 15
src/commands/diffLineWithWorking.ts Datei anzeigen

@ -1,14 +1,14 @@
import { TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitCommit, GitRevision } from '../git/models';
import { GitCommit, GitCommit2, GitRevision } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { ActiveEditorCommand, command, Commands, executeCommand, getCommandUri } from './common';
import { DiffWithCommandArgs } from './diffWith';
export interface DiffLineWithWorkingCommandArgs {
commit?: GitCommit;
commit?: GitCommit | GitCommit2;
line?: number;
showOptions?: TextDocumentShowOptions;
@ -31,6 +31,9 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
args.line = editor?.selection.active.line ?? 0;
}
let lhsSha: string;
let lhsUri: Uri;
if (args.commit == null || args.commit.isUncommitted) {
const blameline = args.line;
if (blameline < 0) return;
@ -47,28 +50,37 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
args.commit = blame.commit;
// If the line is uncommitted, change the previous commit
// If the line is uncommitted, use previous commit (or index if the file is staged)
if (args.commit.isUncommitted) {
const status = await this.container.git.getStatusForFile(gitUri.repoPath!, gitUri.fsPath);
args.commit = args.commit.with({
sha: status?.indexStatus != null ? GitRevision.uncommittedStaged : args.commit.previousSha!,
fileName: args.commit.previousFileName!,
originalFileName: null,
previousSha: null,
previousFileName: null,
});
// editor lines are 0-based
args.line = blame.line.line - 1;
if (status?.indexStatus != null) {
lhsSha = GitRevision.uncommittedStaged;
lhsUri = this.container.git.getAbsoluteUri(
status.originalFileName || status.fileName,
args.commit.repoPath,
);
} else {
lhsSha = args.commit.file!.previousSha ?? GitRevision.deletedOrMissing;
lhsUri = args.commit.file!.previousUri;
}
} else {
lhsSha = args.commit.sha;
lhsUri = args.commit.file!.uri;
}
// editor lines are 0-based
args.line = blame.line.line - 1;
} catch (ex) {
Logger.error(ex, 'DiffLineWithWorkingCommand', `getBlameForLine(${blameline})`);
void Messages.showGenericErrorMessage('Unable to open compare');
return;
}
} else {
lhsSha = args.commit.sha;
lhsUri = args.commit.file?.uri ?? gitUri;
}
const workingUri = await args.commit.getWorkingUri();
const workingUri = await args.commit.file?.getWorkingUri();
if (workingUri == null) {
void window.showWarningMessage('Unable to open compare. File has been deleted from the working tree');
@ -78,8 +90,8 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
void (await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
repoPath: args.commit.repoPath,
lhs: {
sha: args.commit.sha,
uri: args.commit.uri,
sha: lhsSha,
uri: lhsUri,
},
rhs: {
sha: '',

+ 12
- 7
src/commands/diffWith.ts Datei anzeigen

@ -1,7 +1,7 @@
import { commands, Range, TextDocumentShowOptions, Uri, ViewColumn } from 'vscode';
import { BuiltInCommands, GlyphChars } from '../constants';
import type { Container } from '../container';
import { GitCommit, GitRevision } from '../git/models';
import { GitCommit, GitCommit2, GitRevision } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { basename } from '../system/path';
@ -25,10 +25,10 @@ export interface DiffWithCommandArgs {
@command()
export class DiffWithCommand extends Command {
static getMarkdownCommandArgs(args: DiffWithCommandArgs): string;
static getMarkdownCommandArgs(commit: GitCommit, line?: number): string;
static getMarkdownCommandArgs(argsOrCommit: DiffWithCommandArgs | GitCommit, line?: number): string {
let args: DiffWithCommandArgs | GitCommit;
if (GitCommit.is(argsOrCommit)) {
static getMarkdownCommandArgs(commit: GitCommit | GitCommit2, line?: number): string;
static getMarkdownCommandArgs(argsOrCommit: DiffWithCommandArgs | GitCommit | GitCommit2, line?: number): string {
let args: DiffWithCommandArgs | GitCommit | GitCommit2;
if (GitCommit.is(argsOrCommit) || GitCommit2.is(argsOrCommit)) {
const commit = argsOrCommit;
if (commit.isUncommitted) {
@ -45,11 +45,16 @@ export class DiffWithCommand extends Command {
line: line,
};
} else {
if (commit.file == null) {
debugger;
throw new Error('Commit has no file');
}
args = {
repoPath: commit.repoPath,
lhs: {
sha: commit.previousSha != null ? commit.previousSha : GitRevision.deletedOrMissing,
uri: commit.previousUri,
sha: commit.file.previousSha ?? GitRevision.deletedOrMissing,
uri: commit.file.previousUri,
},
rhs: {
sha: commit.sha,

+ 3
- 3
src/commands/diffWithPrevious.ts Datei anzeigen

@ -1,7 +1,7 @@
import { TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitCommit, GitRevision } from '../git/models';
import { GitCommit, GitCommit2, GitRevision } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import {
@ -16,7 +16,7 @@ import {
import { DiffWithCommandArgs } from './diffWith';
export interface DiffWithPreviousCommandArgs {
commit?: GitCommit;
commit?: GitCommit2 | GitCommit;
inDiffRightEditor?: boolean;
uri?: Uri;
@ -58,7 +58,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
repoPath: args.commit.repoPath,
lhs: {
sha: `${args.commit.sha}^`,
uri: args.commit.originalUri,
uri: args.commit.originalUri ?? args.commit.uri,
},
rhs: {
sha: args.commit.sha || '',

+ 5
- 12
src/commands/openCommitOnRemote.ts Datei anzeigen

@ -1,6 +1,7 @@
import { TextEditor, Uri, window } from 'vscode';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitRevision } from '../git/models';
import { RemoteResourceType } from '../git/remotes/provider';
import { Logger } from '../logger';
import { Messages } from '../messages';
@ -81,18 +82,10 @@ export class OpenCommitOnRemoteCommand extends ActiveEditorCommand {
return;
}
let commit = blame.commit;
// If the line is uncommitted, find the previous commit
if (commit.isUncommitted) {
commit = commit.with({
sha: commit.previousSha,
fileName: commit.previousFileName,
previousSha: null,
previousFileName: null,
});
}
args.sha = commit.sha;
// If the line is uncommitted, use previous commit
args.sha = blame.commit.isUncommitted
? blame.commit.file!.previousSha ?? GitRevision.deletedOrMissing
: blame.commit.sha;
}
void (await executeCommand<OpenOnRemoteCommandArgs>(Commands.OpenOnRemote, {

+ 4
- 4
src/commands/showQuickCommit.ts Datei anzeigen

@ -1,7 +1,7 @@
import { TextEditor, Uri } from 'vscode';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitCommit, GitLog, GitLogCommit } from '../git/models';
import { GitCommit, GitCommit2, GitLog, GitLogCommit } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import {
@ -17,7 +17,7 @@ import { executeGitCommand, GitActions } from './gitCommands';
export interface ShowQuickCommitCommandArgs {
repoPath?: string;
sha?: string;
commit?: GitCommit | GitLogCommit;
commit?: GitCommit2 | GitCommit | GitLogCommit;
repoLog?: GitLog;
revealInView?: boolean;
}
@ -115,7 +115,7 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand {
}
try {
if (args.commit == null || args.commit.isFile) {
if (args.commit == null || args.commit.file != null) {
if (args.repoLog != null) {
args.commit = args.repoLog.commits.get(args.sha);
// If we can't find the commit, kill the repoLog
@ -148,7 +148,7 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand {
void (await executeGitCommand({
command: 'show',
state: {
repo: repoPath!,
repo: repoPath,
reference: args.commit as GitLogCommit,
},
}));

+ 22
- 16
src/commands/showQuickCommitFile.ts Datei anzeigen

@ -1,7 +1,7 @@
import { TextEditor, Uri, window } from 'vscode';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitBlameCommit, GitCommit, GitLog, GitLogCommit } from '../git/models';
import { GitCommit2, GitLog, GitLogCommit } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import {
@ -16,7 +16,7 @@ import { executeGitCommand } from './gitCommands';
export interface ShowQuickCommitFileCommandArgs {
sha?: string;
commit?: GitCommit | GitLogCommit;
commit?: GitCommit2 | GitLogCommit;
fileLog?: GitLog;
revisionUri?: string;
}
@ -49,7 +49,7 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
args.sha = context.node.uri.sha;
if (isCommandContextViewNodeHasCommit(context)) {
args.commit = context.node.commit;
args.commit = context.node.commit as any;
}
}
@ -103,21 +103,21 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
}
try {
if (args.commit === undefined || !args.commit.isFile) {
if (args.fileLog !== undefined) {
if (args.commit == null /*|| args.commit.file != null*/) {
if (args.fileLog != null) {
args.commit = args.fileLog.commits.get(args.sha);
// If we can't find the commit, kill the fileLog
if (args.commit === undefined) {
if (args.commit == null) {
args.fileLog = undefined;
}
}
if (args.fileLog === undefined) {
const repoPath = args.commit === undefined ? gitUri.repoPath : args.commit.repoPath;
if (args.fileLog == null) {
const repoPath = args.commit?.repoPath ?? gitUri.repoPath;
args.commit = await this.container.git.getCommitForFile(repoPath, gitUri, {
ref: args.sha,
});
if (args.commit === undefined) {
if (args.commit == null) {
void Messages.showCommitNotFoundWarningMessage('Unable to show commit file details');
return;
@ -125,25 +125,31 @@ export class ShowQuickCommitFileCommand extends ActiveEditorCachedCommand {
}
}
if (args.commit === undefined) {
if (args.commit == null) {
void Messages.showCommitNotFoundWarningMessage('Unable to show commit file details');
return;
}
const path = args.commit?.file?.path ?? gitUri.fsPath;
if (GitCommit2.is(args.commit)) {
if (args.commit.files == null) {
await args.commit.ensureFullDetails();
}
}
// const shortSha = GitRevision.shorten(args.sha);
const fileName = args.commit.fileName;
if (args.commit instanceof GitBlameCommit) {
args.commit = (await this.container.git.getCommit(args.commit.repoPath, args.commit.ref))!;
}
// if (args.commit instanceof GitBlameCommit) {
// args.commit = (await this.container.git.getCommit(args.commit.repoPath, args.commit.ref))!;
// }
void (await executeGitCommand({
command: 'show',
state: {
repo: args.commit.repoPath,
reference: args.commit as GitLogCommit,
fileName: fileName,
reference: args.commit,
fileName: path,
},
}));

+ 13
- 13
src/env/node/git/localGitProvider.ts Datei anzeigen

@ -42,11 +42,11 @@ import {
BranchSortOptions,
GitAuthor,
GitBlame,
GitBlameCommit,
GitBlameLine,
GitBlameLines,
GitBranch,
GitBranchReference,
GitCommit2,
GitCommitType,
GitContributor,
GitDiff,
@ -1083,7 +1083,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const commit = blame.commits.get(blameLine.sha);
if (commit == null) return undefined;
const author = blame.authors.get(commit.author)!;
const author = blame.authors.get(commit.author.name)!;
return {
author: { ...author, lineCount: commit.lines.length },
commit: commit,
@ -1134,7 +1134,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const commit = blame.commits.get(blameLine.sha);
if (commit == null) return undefined;
const author = blame.authors.get(commit.author)!;
const author = blame.authors.get(commit.author.name)!;
return {
author: { ...author, lineCount: commit.lines.length },
commit: commit,
@ -1197,7 +1197,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
const endLine = range.end.line + 1;
const authors = new Map<string, GitAuthor>();
const commits = new Map<string, GitBlameCommit>();
const commits = new Map<string, GitCommit2>();
for (const c of blame.commits.values()) {
if (!shas.has(c.sha)) continue;
@ -1206,10 +1206,10 @@ export class LocalGitProvider implements GitProvider, Disposable {
});
commits.set(c.sha, commit);
let author = authors.get(commit.author);
let author = authors.get(commit.author.name);
if (author == null) {
author = {
name: commit.author,
name: commit.author.name,
lineCount: 0,
};
authors.set(author.name, author);
@ -2261,7 +2261,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
return undefined;
}
authors.set(c.author, log.authors.get(c.author)!);
authors.set(c.author.name, log.authors.get(c.author.name)!);
return [ref, c];
},
),
@ -2839,12 +2839,12 @@ export class LocalGitProvider implements GitProvider, Disposable {
// If line is committed, diff with line ref with previous
else {
ref = blameLine.commit.sha;
path = blameLine.commit.fileName || (blameLine.commit.originalFileName ?? path);
path = blameLine.commit.file?.path ?? blameLine.commit.file?.originalPath ?? path;
uri = this.getAbsoluteUri(path, repoPath);
editorLine = blameLine.line.originalLine - 1;
if (skip === 0 && blameLine.commit.previousSha) {
previous = GitUri.fromFile(path, repoPath, blameLine.commit.previousSha);
if (skip === 0 && blameLine.commit.file?.previousSha) {
previous = GitUri.fromFile(path, repoPath, blameLine.commit.file.previousSha);
}
}
} else {
@ -2868,12 +2868,12 @@ export class LocalGitProvider implements GitProvider, Disposable {
// Diff with line ref with previous
ref = blameLine.commit.sha;
path = blameLine.commit.fileName || (blameLine.commit.originalFileName ?? path);
path = blameLine.commit.file?.path ?? blameLine.commit.file?.originalPath ?? path;
uri = this.getAbsoluteUri(path, repoPath);
editorLine = blameLine.line.originalLine - 1;
if (skip === 0 && blameLine.commit.previousSha) {
previous = GitUri.fromFile(path, repoPath, blameLine.commit.previousSha);
if (skip === 0 && blameLine.commit.file?.previousSha) {
previous = GitUri.fromFile(path, repoPath, blameLine.commit.file.previousSha);
}
}

+ 72
- 59
src/git/formatters/commitFormatter.ts Datei anzeigen

@ -19,12 +19,18 @@ import { Iterables, Strings } from '../../system';
import { PromiseCancelledError } from '../../system/promise';
import { ContactPresence } from '../../vsls/vsls';
import type { GitUri } from '../gitUri';
import { GitCommit, GitLogCommit, GitRemote, GitRevision, IssueOrPullRequest, PullRequest } from '../models';
import {
GitCommit,
GitCommit2,
GitLogCommit,
GitRemote,
GitRevision,
IssueOrPullRequest,
PullRequest,
} from '../models';
import { RemoteProvider } from '../remotes/provider';
import { FormatOptions, Formatter } from './formatter';
const emptyStr = '';
export interface CommitFormatOptions extends FormatOptions {
autolinkedIssuesOrPullRequests?: Map<string, IssueOrPullRequest | PromiseCancelledError | undefined>;
avatarSize?: number;
@ -77,29 +83,29 @@ export interface CommitFormatOptions extends FormatOptions {
};
}
export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> {
export class CommitFormatter extends Formatter<GitCommit | GitCommit2, CommitFormatOptions> {
private get _authorDate() {
return this._item.formatAuthorDate(this._options.dateFormat);
return this._item.author.formatDate(this._options.dateFormat);
}
private get _authorDateAgo() {
return this._item.formatAuthorDateFromNow();
return this._item.author.fromNow();
}
private get _authorDateAgoShort() {
return this._item.formatCommitterDateFromNow(true);
return this._item.author.fromNow(true);
}
private get _committerDate() {
return this._item.formatCommitterDate(this._options.dateFormat);
return this._item.committer.formatDate(this._options.dateFormat);
}
private get _committerDateAgo() {
return this._item.formatCommitterDateFromNow();
return this._item.committer.fromNow();
}
private get _committerDateAgoShort() {
return this._item.formatCommitterDateFromNow(true);
return this._item.committer.fromNow(true);
}
private get _date() {
@ -116,16 +122,16 @@ export class CommitFormatter extends Formatter {
private get _pullRequestDate() {
const { pullRequestOrRemote: pr } = this._options;
if (pr == null || !PullRequest.is(pr)) return emptyStr;
if (pr == null || !PullRequest.is(pr)) return '';
return pr.formatDate(this._options.dateFormat) ?? emptyStr;
return pr.formatDate(this._options.dateFormat) ?? '';
}
private get _pullRequestDateAgo() {
const { pullRequestOrRemote: pr } = this._options;
if (pr == null || !PullRequest.is(pr)) return emptyStr;
if (pr == null || !PullRequest.is(pr)) return '';
return pr.formatDateFromNow() ?? emptyStr;
return pr.formatDateFromNow() ?? '';
}
private get _pullRequestDateOrAgo() {
@ -157,12 +163,11 @@ export class CommitFormatter extends Formatter {
}
get author(): string {
const author = this._padOrTruncate(this._item.author, this._options.tokenOptions.author);
if (!this._options.markdown) {
return author;
}
const { name, email } = this._item.author;
const author = this._padOrTruncate(name, this._options.tokenOptions.author);
if (!this._options.markdown) return author;
return `[${author}](mailto:${this._item.email} "Email ${this._item.author} (${this._item.email})")`;
return `[${author}](mailto:${email} "Email ${name} (${email})")`;
}
get authorAgo(): string {
@ -192,25 +197,26 @@ export class CommitFormatter extends Formatter {
}
get authorNotYou(): string {
if (this._item.author === 'You') return this._padOrTruncate(emptyStr, this._options.tokenOptions.authorNotYou);
const { name, email } = this._item.author;
if (name === 'You') return this._padOrTruncate('', this._options.tokenOptions.authorNotYou);
const author = this._padOrTruncate(this._item.author, this._options.tokenOptions.authorNotYou);
if (!this._options.markdown) {
return author;
}
const author = this._padOrTruncate(name, this._options.tokenOptions.authorNotYou);
if (!this._options.markdown) return author;
return `[${author}](mailto:${this._item.email} "Email ${this._item.author} (${this._item.email})")`;
return `[${author}](mailto:${email} "Email ${name} (${email})")`;
}
get avatar(): string | Promise<string> {
if (!this._options.markdown || !Container.instance.config.hovers.avatars) {
return this._padOrTruncate(emptyStr, this._options.tokenOptions.avatar);
return this._padOrTruncate('', this._options.tokenOptions.avatar);
}
const { name } = this._item.author;
const presence = this._options.presence;
if (presence != null) {
const title = `${this._item.author} ${this._item.author === 'You' ? 'are' : 'is'} ${
presence.status === 'dnd' ? 'in ' : emptyStr
const title = `${name} ${name === 'You' ? 'are' : 'is'} ${
presence.status === 'dnd' ? 'in ' : ''
}${presence.statusText.toLocaleLowerCase()}`;
const avatarMarkdownPromise = this._getAvatarMarkdown(title, this._options.avatarSize);
@ -222,7 +228,7 @@ export class CommitFormatter extends Formatter {
);
}
return this._getAvatarMarkdown(this._item.author, this._options.avatarSize);
return this._getAvatarMarkdown(name, this._options.avatarSize);
}
private async _getAvatarMarkdown(title: string, size?: number) {
@ -243,31 +249,27 @@ export class CommitFormatter extends Formatter {
get changes(): string {
return this._padOrTruncate(
GitLogCommit.is(this._item) ? this._item.getFormattedDiffStatus() : emptyStr,
GitLogCommit.is(this._item) ? this._item.getFormattedDiffStatus() : '',
this._options.tokenOptions.changes,
);
}
get changesDetail(): string {
return this._padOrTruncate(
GitLogCommit.is(this._item)
? this._item.getFormattedDiffStatus({ expand: true, separator: ', ' })
: emptyStr,
GitLogCommit.is(this._item) ? this._item.getFormattedDiffStatus({ expand: true, separator: ', ' }) : '',
this._options.tokenOptions.changesDetail,
);
}
get changesShort(): string {
return this._padOrTruncate(
GitLogCommit.is(this._item)
? this._item.getFormattedDiffStatus({ compact: true, separator: emptyStr })
: emptyStr,
GitLogCommit.is(this._item) ? this._item.getFormattedDiffStatus({ compact: true, separator: '' }) : '',
this._options.tokenOptions.changesShort,
);
}
get commands(): string {
if (!this._options.markdown) return this._padOrTruncate(emptyStr, this._options.tokenOptions.commands);
if (!this._options.markdown) return this._padOrTruncate('', this._options.tokenOptions.commands);
let commands;
if (this._item.isUncommitted) {
@ -284,11 +286,11 @@ export class CommitFormatter extends Formatter {
commands += ` &nbsp;[$(chevron-left)$(compare-changes)](${DiffWithCommand.getMarkdownCommandArgs({
lhs: {
sha: diffUris.previous.sha ?? emptyStr,
sha: diffUris.previous.sha ?? '',
uri: diffUris.previous.documentUri(),
},
rhs: {
sha: diffUris.current.sha ?? emptyStr,
sha: diffUris.current.sha ?? '',
uri: diffUris.current.documentUri(),
},
repoPath: this._item.repoPath,
@ -370,6 +372,8 @@ export class CommitFormatter extends Formatter {
}
if (Container.instance.actionRunners.count('hover.commands') > 0) {
const { name, email } = this._item.author;
commands += `${separator}[$(organization) Team${GlyphChars.SpaceThinnest}${
GlyphChars.Ellipsis
}](${getMarkdownActionCommand<HoverCommandsActionContext>('hover.commands', {
@ -377,8 +381,8 @@ export class CommitFormatter extends Formatter {
commit: {
sha: this._item.sha,
author: {
name: this._item.author,
email: this._item.email,
name: name,
email: email,
presence: this._options.presence,
},
},
@ -430,13 +434,14 @@ export class CommitFormatter extends Formatter {
}
get email(): string {
return this._padOrTruncate(this._item.email ?? emptyStr, this._options.tokenOptions.email);
const { email } = this._item.author;
return this._padOrTruncate(email ?? '', this._options.tokenOptions.email);
}
get footnotes(): string {
return this._padOrTruncate(
this._options.footnotes == null || this._options.footnotes.size === 0
? emptyStr
? ''
: Iterables.join(
Iterables.map(this._options.footnotes, ([i, footnote]) =>
this._options.markdown ? footnote : `${Strings.getSuperscript(i)} ${footnote}`,
@ -448,7 +453,7 @@ export class CommitFormatter extends Formatter {
}
get id(): string {
const sha = this._padOrTruncate(this._item.shortSha ?? emptyStr, this._options.tokenOptions.id);
const sha = this._padOrTruncate(this._item.shortSha ?? '', this._options.tokenOptions.id);
if (this._options.markdown && this._options.unpublished) {
return `<span style="color:#35b15e;">${sha} (unpublished)</span>`;
}
@ -471,7 +476,7 @@ export class CommitFormatter extends Formatter {
);
}
let message = this._item.message;
let message = this._item.message ?? this._item.summary;
if (this._options.messageTruncateAtNewLine) {
const index = message.indexOf('\n');
if (index !== -1) {
@ -501,7 +506,7 @@ export class CommitFormatter extends Formatter {
get pullRequest(): string {
const { pullRequestOrRemote: pr } = this._options;
if (pr == null) return this._padOrTruncate(emptyStr, this._options.tokenOptions.pullRequest);
if (pr == null) return this._padOrTruncate('', this._options.tokenOptions.pullRequest);
let text;
if (PullRequest.is(pr)) {
@ -543,9 +548,9 @@ export class CommitFormatter extends Formatter {
} else if (pr instanceof PromiseCancelledError) {
text = this._options.markdown
? `[PR $(loading~spin)](command:${Commands.RefreshHover} "Searching for a Pull Request (if any) that introduced this commit...")`
: this._options?.pullRequestPendingMessage ?? emptyStr;
: this._options?.pullRequestPendingMessage ?? '';
} else {
return this._padOrTruncate(emptyStr, this._options.tokenOptions.pullRequest);
return this._padOrTruncate('', this._options.tokenOptions.pullRequest);
}
return this._padOrTruncate(text, this._options.tokenOptions.pullRequest);
@ -566,13 +571,13 @@ export class CommitFormatter extends Formatter {
get pullRequestState(): string {
const { pullRequestOrRemote: pr } = this._options;
return this._padOrTruncate(
pr == null || !PullRequest.is(pr) ? emptyStr : pr.state ?? emptyStr,
pr == null || !PullRequest.is(pr) ? '' : pr.state ?? '',
this._options.tokenOptions.pullRequestState,
);
}
get sha(): string {
return this._padOrTruncate(this._item.shortSha ?? emptyStr, this._options.tokenOptions.sha);
return this._padOrTruncate(this._item.shortSha ?? '', this._options.tokenOptions.sha);
}
get tips(): string {
@ -583,19 +588,19 @@ export class CommitFormatter extends Formatter {
.map(t => `<span style="color:#ffffff;background-color:#1d76db;">&nbsp;&nbsp;${t}&nbsp;&nbsp;</span>`)
.join(GlyphChars.Space.repeat(3));
}
return this._padOrTruncate(branchAndTagTips ?? emptyStr, this._options.tokenOptions.tips);
return this._padOrTruncate(branchAndTagTips ?? '', this._options.tokenOptions.tips);
}
static fromTemplate(template: string, commit: GitCommit, dateFormat: string | null): string;
static fromTemplate(template: string, commit: GitCommit, options?: CommitFormatOptions): string;
static fromTemplate(template: string, commit: GitCommit | GitCommit2, dateFormat: string | null): string;
static fromTemplate(template: string, commit: GitCommit | GitCommit2, options?: CommitFormatOptions): string;
static fromTemplate(
template: string,
commit: GitCommit,
commit: GitCommit | GitCommit2,
dateFormatOrOptions?: string | null | CommitFormatOptions,
): string;
static fromTemplate(
template: string,
commit: GitCommit,
commit: GitCommit | GitCommit2,
dateFormatOrOptions?: string | null | CommitFormatOptions,
): string {
if (dateFormatOrOptions == null || typeof dateFormatOrOptions === 'string') {
@ -618,16 +623,24 @@ export class CommitFormatter extends Formatter {
return super.fromTemplateCore(this, template, commit, dateFormatOrOptions);
}
static fromTemplateAsync(template: string, commit: GitCommit, dateFormat: string | null): Promise<string>;
static fromTemplateAsync(template: string, commit: GitCommit, options?: CommitFormatOptions): Promise<string>;
static fromTemplateAsync(
template: string,
commit: GitCommit,
commit: GitCommit | GitCommit2,
dateFormat: string | null,
): Promise<string>;
static fromTemplateAsync(
template: string,
commit: GitCommit | GitCommit2,
options?: CommitFormatOptions,
): Promise<string>;
static fromTemplateAsync(
template: string,
commit: GitCommit | GitCommit2,
dateFormatOrOptions?: string | null | CommitFormatOptions,
): Promise<string>;
static fromTemplateAsync(
template: string,
commit: GitCommit,
commit: GitCommit | GitCommit2,
dateFormatOrOptions?: string | null | CommitFormatOptions,
): Promise<string> {
if (CommitFormatter.has(template, 'footnotes')) {

+ 6
- 0
src/git/gitProviderService.ts Datei anzeigen

@ -41,6 +41,7 @@ import {
BranchDateFormatting,
BranchSortOptions,
CommitDateFormatting,
CommitShaFormatting,
GitBlame,
GitBlameLine,
GitBlameLines,
@ -155,6 +156,7 @@ export class GitProviderService implements Disposable {
BranchDateFormatting.reset();
CommitDateFormatting.reset();
CommitShaFormatting.reset();
PullRequestDateFormatting.reset();
this.updateContext();
@ -184,6 +186,10 @@ export class GitProviderService implements Disposable {
PullRequestDateFormatting.reset();
}
if (configuration.changed(e, 'advanced.abbreviatedShaLength')) {
CommitShaFormatting.reset();
}
if (configuration.changed(e, 'views.contributors.showAllBranches')) {
this.resetCaches('contributors');
}

+ 2
- 2
src/git/gitUri.ts Datei anzeigen

@ -10,7 +10,7 @@ import { memoize } from '../system/decorators/memoize';
import { basename, dirname, isAbsolute, normalizePath, relative } from '../system/path';
import { CharCode, truncateLeft, truncateMiddle } from '../system/string';
import { RevisionUriData } from './gitProvider';
import { GitCommit, GitFile, GitRevision } from './models';
import { GitCommit, GitCommit2, GitFile, GitRevision } from './models';
export interface GitCommitish {
fileName?: string;
@ -230,7 +230,7 @@ export class GitUri extends (Uri as any as UriEx) {
return Container.instance.git.getAbsoluteUri(this.fsPath, this.repoPath);
}
static fromCommit(commit: GitCommit, previous: boolean = false) {
static fromCommit(commit: GitCommit | GitCommit2, previous: boolean = false) {
if (!previous) return new GitUri(commit.uri, commit);
return new GitUri(commit.previousUri, {

+ 0
- 1
src/git/models.ts Datei anzeigen

@ -1,6 +1,5 @@
export * from './models/author';
export * from './models/blame';
export * from './models/blameCommit';
export * from './models/branch';
export * from './models/commit';
export * from './models/contributor';

+ 4
- 5
src/git/models/blame.ts Datei anzeigen

@ -1,16 +1,15 @@
import { GitBlameCommit } from './blameCommit';
import { GitAuthor, GitCommitLine } from './commit';
import { GitAuthor, GitCommit2, GitCommitLine } from './commit';
export interface GitBlame {
readonly repoPath: string;
readonly authors: Map<string, GitAuthor>;
readonly commits: Map<string, GitBlameCommit>;
readonly commits: Map<string, GitCommit2>;
readonly lines: GitCommitLine[];
}
export interface GitBlameLine {
readonly author?: GitAuthor;
readonly commit: GitBlameCommit;
readonly commit: GitCommit2;
readonly line: GitCommitLine;
}
@ -20,6 +19,6 @@ export interface GitBlameLines extends GitBlame {
export interface GitBlameCommitLines {
readonly author: GitAuthor;
readonly commit: GitBlameCommit;
readonly commit: GitCommit2;
readonly lines: GitCommitLine[];
}

+ 0
- 64
src/git/models/blameCommit.ts Datei anzeigen

@ -1,64 +0,0 @@
import { GitCommit, GitCommitLine, GitCommitType } from './commit';
export class GitBlameCommit extends GitCommit {
static override is(commit: any): commit is GitBlameCommit {
return (
commit instanceof GitBlameCommit
//|| (commit.repoPath !== undefined && commit.sha !== undefined && commit.type === GitCommitType.Blame)
);
}
constructor(
repoPath: string,
sha: string,
author: string,
email: string | undefined,
authorDate: Date,
committerDate: Date,
message: string,
fileName: string,
originalFileName: string | undefined,
previousSha: string | undefined,
previousFileName: string | undefined,
public readonly lines: GitCommitLine[],
) {
super(
GitCommitType.Blame,
repoPath,
sha,
author,
email,
authorDate,
committerDate,
message,
fileName,
originalFileName,
previousSha,
previousFileName,
);
}
with(changes: {
sha?: string;
fileName?: string;
originalFileName?: string | null;
previousFileName?: string | null;
previousSha?: string | null;
lines?: GitCommitLine[] | null;
}): GitBlameCommit {
return new GitBlameCommit(
this.repoPath,
changes.sha ?? this.sha,
this.author,
this.email,
this.authorDate,
this.committerDate,
this.message,
changes.fileName ?? this.fileName,
this.getChangedValue(changes.originalFileName, this.originalFileName),
this.getChangedValue(changes.previousSha, this.previousSha),
this.getChangedValue(changes.previousFileName, this.previousFileName),
this.getChangedValue(changes.lines, changes.sha ?? changes.fileName ? [] : this.lines) ?? [],
);
}
}

+ 312
- 4
src/git/models/commit.ts Datei anzeigen

@ -6,7 +6,14 @@ import { formatDate, fromNow } from '../../system/date';
import { memoize } from '../../system/decorators/memoize';
import { CommitFormatter } from '../formatters';
import { GitUri } from '../gitUri';
import { GitReference, GitRevision, GitRevisionReference, PullRequest } from '../models';
import {
GitFileIndexStatus,
GitFileStatus,
GitReference,
GitRevision,
GitRevisionReference,
PullRequest,
} from '../models';
export interface GitAuthor {
name: string;
@ -41,7 +48,308 @@ export const CommitDateFormatting = {
},
};
export const CommitShaFormatting = {
length: undefined! as number,
reset: () => {
// Don't allow shas to be shortened to less than 5 characters
CommitShaFormatting.length = Math.max(5, Container.instance.config.advanced.abbreviatedShaLength);
},
};
export class GitCommitIdentity {
constructor(
public readonly name: string,
public readonly email: string | undefined,
public readonly date: Date,
private readonly avatarUrl?: string | undefined,
) {}
@memoize<GitCommitIdentity['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return formatDate(this.date, format);
}
fromNow(short?: boolean) {
return fromNow(this.date, short);
}
getAvatarUri(
commit: GitCommit2,
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri> {
if (this.avatarUrl != null) Uri.parse(this.avatarUrl);
return getAvatarUri(this.email, commit, options);
}
}
export class GitFileChange {
constructor(
public readonly repoPath: string,
public readonly path: string,
public readonly status: GitFileStatus,
public readonly originalPath?: string | undefined,
public readonly previousSha?: string | undefined,
) {}
@memoize()
get uri(): Uri {
return Container.instance.git.getAbsoluteUri(this.path, this.repoPath);
}
@memoize()
get originalUri(): Uri | undefined {
return this.originalPath ? Container.instance.git.getAbsoluteUri(this.originalPath, this.repoPath) : undefined;
}
@memoize()
get previousUri(): Uri {
return Container.instance.git.getAbsoluteUri(this.originalPath || this.path, this.repoPath);
}
@memoize()
getWorkingUri(): Promise<Uri | undefined> {
return Container.instance.git.getWorkingUri(this.repoPath, this.uri);
}
}
const stashNumberRegex = /stash@{(\d+)}/;
export class GitCommit2 implements GitRevisionReference {
static is(commit: any): commit is GitCommit2 {
return commit instanceof GitCommit2;
}
static hasFullDetails(commit: GitCommit2): commit is GitCommit2 & SomeNonNullable<GitCommit2, 'message' | 'files'> {
return commit.message != null && commit.files != null && commit.parents.length !== 0;
}
static isOfRefType(commit: GitReference | undefined) {
return commit?.refType === 'revision' || commit?.refType === 'stash';
}
readonly lines: GitCommitLine[];
readonly ref: string;
readonly refType: GitRevisionReference['refType'];
readonly shortSha: string;
readonly stashName: string | undefined;
readonly stashNumber: number | undefined;
constructor(
public readonly repoPath: string,
public readonly sha: string,
public readonly author: GitCommitIdentity,
public readonly committer: GitCommitIdentity,
public readonly summary: string,
public readonly parents: string[],
message?: string | undefined,
files?: GitFileChange | GitFileChange[] | undefined,
lines?: GitCommitLine | GitCommitLine[] | undefined,
stashName?: string | undefined,
) {
this.ref = this.sha;
this.refType = 'revision';
this.shortSha = this.sha.substring(0, CommitShaFormatting.length);
if (message != null) {
this._message = message;
}
if (files != null) {
if (Array.isArray(files)) {
this._files = files;
} else {
this._file = files;
}
}
if (lines != null) {
if (Array.isArray(lines)) {
this.lines = lines;
} else {
this.lines = [lines];
}
} else {
this.lines = [];
}
if (stashName) {
this.stashName = stashName || undefined;
this.stashNumber = Number(stashNumberRegex.exec(stashName)?.[1]);
}
}
get date(): Date {
return CommitDateFormatting.dateSource === DateSource.Committed ? this.committer.date : this.author.date;
}
private _file: GitFileChange | undefined;
get file(): GitFileChange | undefined {
return this._file;
}
private _files: GitFileChange[] | undefined;
get files(): GitFileChange[] | undefined {
return this._files;
}
get formattedDate(): string {
return CommitDateFormatting.dateStyle === DateStyle.Absolute
? this.formatDate(CommitDateFormatting.dateFormat)
: this.formatDateFromNow();
}
get hasConflicts(): boolean | undefined {
return undefined;
// return this._files?.some(f => f.conflictStatus != null);
}
private _message: string | undefined;
get message(): string | undefined {
return this._message;
}
get name() {
return this.stashName ? this.stashName : this.shortSha;
}
@memoize()
get isUncommitted(): boolean {
return GitRevision.isUncommitted(this.sha);
}
@memoize()
get isUncommittedStaged(): boolean {
return GitRevision.isUncommittedStaged(this.sha);
}
/** @deprecated use `file.uri` */
get uri(): Uri /*| undefined*/ {
return this.file?.uri ?? Container.instance.git.getAbsoluteUri(this.repoPath, this.repoPath);
}
/** @deprecated use `file.originalUri` */
get originalUri(): Uri | undefined {
return this.file?.originalUri;
}
/** @deprecated use `file.getWorkingUri` */
getWorkingUri(): Promise<Uri | undefined> {
return Promise.resolve(this.file?.getWorkingUri());
}
/** @deprecated use `file.previousUri` */
get previousUri(): Uri /*| undefined*/ {
return this.file?.previousUri ?? Container.instance.git.getAbsoluteUri(this.repoPath, this.repoPath);
}
/** @deprecated use `file.previousSha` */
get previousSha(): string | undefined {
return this.file?.previousSha;
}
async ensureFullDetails(): Promise<void> {
if (this.isUncommitted || GitCommit2.hasFullDetails(this)) return;
const commit = await Container.instance.git.getCommit(this.repoPath, this.sha);
if (commit == null) return;
this.parents.push(...(commit.parentShas ?? []));
this._message = commit.message;
this._files = commit.files.map(f => new GitFileChange(this.repoPath, f.fileName, f.status, f.originalFileName));
}
formatDate(format?: string | null) {
return CommitDateFormatting.dateSource === DateSource.Committed
? this.committer.formatDate(format)
: this.author.formatDate(format);
}
formatDateFromNow(short?: boolean) {
return CommitDateFormatting.dateSource === DateSource.Committed
? this.committer.fromNow(short)
: this.author.fromNow(short);
}
// TODO@eamodio deal with memoization, since we don't want the timeout to apply
@memoize()
async getAssociatedPullRequest(options?: { timeout?: number }): Promise<PullRequest | undefined> {
const remote = await Container.instance.git.getRichRemoteProvider(this.repoPath);
if (remote?.provider == null) return undefined;
return Container.instance.git.getPullRequestForCommit(this.ref, remote, options);
}
getAvatarUri(options?: { defaultStyle?: GravatarDefaultStyle; size?: number }): Uri | Promise<Uri> {
return this.author.getAvatarUri(this, options);
}
@memoize<GitCommit['getPreviousLineDiffUris']>((u, e, r) => `${u.toString()}|${e}|${r ?? ''}`)
getPreviousLineDiffUris(uri: Uri, editorLine: number, ref: string | undefined) {
return this.file?.path
? Container.instance.git.getPreviousLineDiffUris(this.repoPath, uri, editorLine, ref)
: Promise.resolve(undefined);
}
@memoize()
toGitUri(previous: boolean = false): GitUri {
return GitUri.fromCommit(this, previous);
}
with(changes: {
sha?: string;
parents?: string[];
files?: GitFileChange | GitFileChange[] | null;
lines?: GitCommitLine[];
}): GitCommit2 {
return new GitCommit2(
this.repoPath,
changes.sha ?? this.sha,
this.author,
this.committer,
this.summary,
this.getChangedValue(changes.parents, this.parents) ?? [],
this.message,
this.getChangedValue(changes.files, this.files),
this.getChangedValue(changes.lines, this.lines),
this.stashName,
);
}
protected getChangedValue<T>(change: T | null | undefined, original: T | undefined): T | undefined {
if (change === undefined) return original;
return change !== null ? change : undefined;
}
}
export abstract class GitCommit implements GitRevisionReference {
get file() {
return this.fileName
? new GitFileChange(this.repoPath, this.fileName, GitFileIndexStatus.Modified, this.originalFileName)
: undefined;
}
get parents(): string[] {
return this.previousSha ? [this.previousSha] : [];
}
get summary(): string {
return this.message.split('\n', 1)[0];
}
get author(): GitCommitIdentity {
return new GitCommitIdentity(this.authorName, this.authorEmail, this.authorDate);
}
get committer(): GitCommitIdentity {
return new GitCommitIdentity('', '', this.committerDate);
}
static is(commit: any): commit is GitCommit {
return commit instanceof GitCommit;
}
@ -56,8 +364,8 @@ export abstract class GitCommit implements GitRevisionReference {
public readonly type: GitCommitType,
public readonly repoPath: string,
public readonly sha: string,
public readonly author: string,
public readonly email: string | undefined,
public readonly authorName: string,
public readonly authorEmail: string | undefined,
public readonly authorDate: Date,
public readonly committerDate: Date,
public readonly message: string,
@ -209,7 +517,7 @@ export abstract class GitCommit implements GitRevisionReference {
}
getAvatarUri(options?: { defaultStyle?: GravatarDefaultStyle; size?: number }): Uri | Promise<Uri> {
return getAvatarUri(this.email, this, options);
return getAvatarUri(this.authorEmail, this, options);
}
@memoize()

+ 1
- 1
src/git/models/file.ts Datei anzeigen

@ -32,7 +32,7 @@ export const enum GitFileWorkingTreeStatus {
}
export interface GitFile {
status: GitFileConflictStatus | GitFileIndexStatus | GitFileWorkingTreeStatus;
status: GitFileStatus;
readonly repoPath?: string;
readonly conflictStatus?: GitFileConflictStatus;
readonly indexStatus?: GitFileIndexStatus;

+ 24
- 6
src/git/models/logCommit.ts Datei anzeigen

@ -3,8 +3,8 @@ import { Container } from '../../container';
import { memoize, Strings } from '../../system';
import { GitUri } from '../gitUri';
import { GitReference } from '../models';
import { GitCommit, GitCommitType } from './commit';
import { GitFile, GitFileStatus } from './file';
import { GitCommit, GitCommitType, GitFileChange } from './commit';
import { GitFile, GitFileIndexStatus, GitFileStatus } from './file';
const emptyStats = Object.freeze({
added: 0,
@ -24,6 +24,10 @@ export interface GitLogCommitLine {
}
export class GitLogCommit extends GitCommit {
override get parents(): string[] {
return this.parentShas != null ? this.parentShas : [];
}
static override isOfRefType(commit: GitReference | undefined) {
return commit?.refType === 'revision';
}
@ -39,6 +43,7 @@ export class GitLogCommit extends GitCommit {
nextSha?: string;
nextFileName?: string;
readonly lines: GitLogCommitLine[];
constructor(
type: GitCommitType,
@ -62,7 +67,7 @@ export class GitLogCommit extends GitCommit {
}
| undefined,
public readonly parentShas?: string[],
public readonly line?: GitLogCommitLine,
lines?: GitLogCommitLine[],
) {
super(
type,
@ -78,6 +83,19 @@ export class GitLogCommit extends GitCommit {
previousSha ?? `${sha}^`,
previousFileName,
);
this.lines = lines ?? [];
}
override get file() {
return this.isFile
? new GitFileChange(
this.repoPath,
this.fileName,
this.status ?? GitFileIndexStatus.Modified,
this.originalFileName,
)
: undefined;
}
@memoize()
@ -222,8 +240,8 @@ export class GitLogCommit extends GitCommit {
changes.type ?? this.type,
this.repoPath,
this.getChangedValue(changes.sha, this.sha)!,
changes.author ?? this.author,
changes.email ?? this.email,
changes.author ?? this.authorName,
changes.email ?? this.authorEmail,
changes.authorDate ?? this.authorDate,
changes.committedDate ?? this.committerDate,
changes.message ?? this.message,
@ -235,7 +253,7 @@ export class GitLogCommit extends GitCommit {
this.getChangedValue(changes.previousFileName, this.previousFileName),
this._fileStats,
this.parentShas,
this.line,
this.lines,
);
}
}

+ 77
- 38
src/git/parsers/blameParser.ts Datei anzeigen

@ -1,9 +1,17 @@
import { debug, Strings } from '../../system';
import { debug } from '../../system/decorators/log';
import { normalizePath, relative } from '../../system/path';
import { GitAuthor, GitBlame, GitBlameCommit, GitCommitLine, GitRevision, GitUser } from '../models';
const emptyStr = '';
const slash = '/';
import { getLines } from '../../system/string';
import {
GitAuthor,
GitBlame,
GitCommit2,
GitCommitIdentity,
GitCommitLine,
GitFileChange,
GitFileIndexStatus,
GitRevision,
GitUser,
} from '../models';
interface BlameEntry {
sha: string;
@ -17,8 +25,10 @@ interface BlameEntry {
authorTimeZone?: string;
authorEmail?: string;
committer: string;
committerDate?: string;
committerTimeZone?: string;
committerEmail?: string;
previousSha?: string;
previousFileName?: string;
@ -39,7 +49,7 @@ export class GitBlameParser {
if (!data) return undefined;
const authors = new Map<string, GitAuthor>();
const commits = new Map<string, GitBlameCommit>();
const commits = new Map<string, GitCommit2>();
const lines: GitCommitLine[] = [];
let relativeFileName;
@ -50,13 +60,14 @@ export class GitBlameParser {
let first = true;
for (line of Strings.lines(data)) {
for (line of getLines(data)) {
lineParts = line.split(' ');
if (lineParts.length < 2) continue;
if (entry === undefined) {
entry = {
author: undefined!,
committer: undefined!,
sha: lineParts[0],
originalLine: parseInt(lineParts[1], 10),
line: parseInt(lineParts[2], 10),
@ -102,6 +113,33 @@ export class GitBlameParser {
entry.authorTimeZone = lineParts[1];
break;
case 'committer':
if (GitRevision.isUncommitted(entry.sha)) {
entry.committer = 'You';
} else {
entry.committer = lineParts.slice(1).join(' ').trim();
}
break;
case 'committer-mail': {
if (GitRevision.isUncommitted(entry.sha)) {
entry.committerEmail = currentUser !== undefined ? currentUser.email : undefined;
continue;
}
entry.committerEmail = lineParts.slice(1).join(' ').trim();
const start = entry.committerEmail.indexOf('<');
if (start >= 0) {
const end = entry.committerEmail.indexOf('>', start);
if (end > start) {
entry.committerEmail = entry.committerEmail.substring(start + 1, end);
} else {
entry.committerEmail = entry.committerEmail.substring(start + 1);
}
}
break;
}
case 'committer-time':
entry.committerDate = lineParts[1];
break;
@ -125,10 +163,7 @@ export class GitBlameParser {
if (first && repoPath === undefined) {
// Try to get the repoPath from the most recent commit
repoPath = normalizePath(
fileName.replace(
fileName.startsWith(slash) ? `/${entry.fileName}` : entry.fileName,
emptyStr,
),
fileName.replace(fileName.startsWith('/') ? `/${entry.fileName}` : entry.fileName, ''),
);
relativeFileName = normalizePath(relative(repoPath, fileName));
} else {
@ -147,10 +182,10 @@ export class GitBlameParser {
}
for (const [, c] of commits) {
if (c.author === undefined) return undefined;
if (!c.author.name) continue;
const author = authors.get(c.author);
if (author === undefined) return undefined;
const author = authors.get(c.author.name);
if (author == undefined) return undefined;
author.lineCount += c.lines.length;
}
@ -170,28 +205,28 @@ export class GitBlameParser {
entry: BlameEntry,
repoPath: string | undefined,
relativeFileName: string,
commits: Map<string, GitBlameCommit>,
commits: Map<string, GitCommit2>,
authors: Map<string, GitAuthor>,
lines: GitCommitLine[],
currentUser: { name?: string; email?: string } | undefined,
) {
let commit = commits.get(entry.sha);
if (commit === undefined) {
if (entry.author !== undefined) {
if (commit == null) {
if (entry.author != null) {
if (
currentUser !== undefined &&
currentUser != null &&
// Name or e-mail is configured
(currentUser.name !== undefined || currentUser.email !== undefined) &&
(currentUser.name != null || currentUser.email != null) &&
// Match on name if configured
(currentUser.name === undefined || currentUser.name === entry.author) &&
(currentUser.name == null || currentUser.name === entry.author) &&
// Match on email if configured
(currentUser.email === undefined || currentUser.email === entry.authorEmail)
(currentUser.email == null || currentUser.email === entry.authorEmail)
) {
entry.author = 'You';
}
let author = authors.get(entry.author);
if (author === undefined) {
if (author == null) {
author = {
name: entry.author,
lineCount: 0,
@ -200,20 +235,27 @@ export class GitBlameParser {
}
}
commit = new GitBlameCommit(
commit = new GitCommit2(
repoPath!,
entry.sha,
entry.author,
entry.authorEmail,
new Date((entry.authorDate as any) * 1000),
new Date((entry.committerDate as any) * 1000),
new GitCommitIdentity(entry.author, entry.authorEmail, new Date((entry.authorDate as any) * 1000)),
new GitCommitIdentity(
entry.committer,
entry.committerEmail,
new Date((entry.committerDate as any) * 1000),
),
entry.summary!,
relativeFileName,
entry.previousFileName !== undefined && entry.previousFileName !== entry.fileName
? entry.previousFileName
: undefined,
entry.previousSha,
entry.previousSha && entry.previousFileName,
[],
undefined,
new GitFileChange(
repoPath!,
relativeFileName,
GitFileIndexStatus.Modified,
entry.previousFileName && entry.previousFileName !== entry.fileName
? entry.previousFileName
: undefined,
entry.previousSha,
),
[],
);
@ -225,13 +267,10 @@ export class GitBlameParser {
sha: entry.sha,
line: entry.line + i,
originalLine: entry.originalLine + i,
previousSha: commit.file?.previousSha,
};
if (commit.previousSha) {
line.previousSha = commit.previousSha;
}
commit.lines.push(line);
commit.lines?.push(line);
lines[line.line - 1] = line;
}
}

+ 1
- 1
src/git/parsers/diffParser.ts Datei anzeigen

@ -81,7 +81,7 @@ export class GitDiffParser {
let hasRemoved;
let removed = 0;
for (const l of Strings.lines(hunk.diff)) {
for (const l of Strings.getLines(hunk.diff)) {
switch (l[0]) {
case '+':
hasAddedOrChanged = true;

+ 4
- 3
src/git/parsers/logParser.ts Datei anzeigen

@ -1,6 +1,7 @@
import { Range } from 'vscode';
import { Arrays, debug, Strings } from '../../system';
import { Arrays, debug } from '../../system';
import { normalizePath, relative } from '../../system/path';
import { getLines } from '../../system/string';
import {
GitAuthor,
GitCommitType,
@ -105,7 +106,7 @@ export class GitLogParser {
let i = 0;
let first = true;
const lines = Strings.lines(`${data}</f>`);
const lines = getLines(`${data}</f>`);
// Skip the first line since it will always be </f>
let next = lines.next();
if (next.done) return undefined;
@ -455,7 +456,7 @@ export class GitLogParser {
undefined,
entry.fileStats,
entry.parentShas,
entry.line,
entry.line != null ? [entry.line] : [],
);
commits.set(entry.ref!, commit);

+ 1
- 1
src/git/parsers/stashParser.ts Datei anzeigen

@ -40,7 +40,7 @@ export class GitStashParser {
static parse(data: string, repoPath: string): GitStash | undefined {
if (!data) return undefined;
const lines = Strings.lines(`${data}</f>`);
const lines = Strings.getLines(`${data}</f>`);
// Skip the first line since it will always be </f>
let next = lines.next();
if (next.done) return undefined;

+ 41
- 34
src/hovers/hovers.ts Datei anzeigen

@ -6,8 +6,7 @@ import { Container } from '../container';
import { CommitFormatter } from '../git/formatters';
import { GitUri } from '../git/gitUri';
import {
GitBlameCommit,
GitCommit,
GitCommit2,
GitDiffHunk,
GitDiffHunkLine,
GitLogCommit,
@ -16,12 +15,13 @@ import {
PullRequest,
} from '../git/models';
import { Logger, LogLevel } from '../logger';
import { Iterables, Strings } from '../system';
import { count } from '../system/iterable';
import { PromiseCancelledError } from '../system/promise';
import { getDurationMilliseconds } from '../system/string';
export namespace Hovers {
export async function changesMessage(
commit: GitBlameCommit | GitLogCommit,
commit: GitCommit2,
uri: GitUri,
editorLine: number,
document: TextDocument,
@ -29,7 +29,7 @@ export namespace Hovers {
const documentRef = uri.sha;
async function getDiff() {
if (!GitBlameCommit.is(commit)) return undefined;
if (commit.file == null) return undefined;
// TODO: Figure out how to optimize this
let ref;
@ -38,7 +38,7 @@ export namespace Hovers {
ref = documentRef;
}
} else {
ref = commit.previousSha;
ref = commit.file.previousSha;
if (ref == null) {
return `\`\`\`diff\n+ ${document.lineAt(editorLine).text}\n\`\`\``;
}
@ -47,10 +47,10 @@ export namespace Hovers {
const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) ?? commit.lines[0];
let originalFileName = commit.originalFileName;
if (originalFileName == null) {
if (uri.fsPath !== commit.uri.fsPath) {
originalFileName = commit.fileName;
let originalPath = commit.file.originalPath;
if (originalPath == null) {
if (uri.fsPath !== commit.file.uri.fsPath) {
originalPath = commit.file.path;
}
}
@ -96,9 +96,7 @@ export namespace Hovers {
previous =
diffUris.previous.sha == null || diffUris.previous.isUncommitted
? ` &nbsp;_${GitRevision.shorten(diffUris.previous.sha, {
strings: {
working: 'Working Tree',
},
strings: { working: 'Working Tree' },
})}_ &nbsp;${GlyphChars.ArrowLeftRightLong}&nbsp; `
: ` &nbsp;[$(git-commit) ${GitRevision.shorten(
diffUris.previous.sha || '',
@ -122,10 +120,11 @@ export namespace Hovers {
editorLine,
)} "Open Changes")`;
if (commit.previousSha) {
previous = ` &nbsp;[$(git-commit) ${
commit.previousShortSha
}](${ShowQuickCommitCommand.getMarkdownCommandArgs(commit.previousSha)} "Show Commit") &nbsp;${
const previousSha = commit.file?.previousSha;
if (previousSha) {
previous = ` &nbsp;[$(git-commit) ${GitRevision.shorten(
previousSha,
)}](${ShowQuickCommitCommand.getMarkdownCommandArgs(previousSha)} "Show Commit") &nbsp;${
GlyphChars.ArrowLeftRightLong
}&nbsp;`;
}
@ -190,7 +189,7 @@ export namespace Hovers {
}
export async function detailsMessage(
commit: GitCommit,
commit: GitCommit2,
uri: GitUri,
editorLine: number,
format: string,
@ -212,13 +211,21 @@ export namespace Hovers {
dateFormat = 'MMMM Do, YYYY h:mma';
}
let message = commit.message ?? commit.summary;
if (commit.message == null && !commit.isUncommitted) {
await commit.ensureFullDetails();
message = commit.message ?? commit.summary;
if (options?.cancellationToken?.isCancellationRequested) return new MarkdownString();
}
const remotes = await Container.instance.git.getRemotesWithProviders(commit.repoPath, { sort: true });
if (options?.cancellationToken?.isCancellationRequested) return new MarkdownString();
const [previousLineDiffUris, autolinkedIssuesOrPullRequests, pr, presence] = await Promise.all([
commit.isUncommitted ? commit.getPreviousLineDiffUris(uri, editorLine, uri.sha) : undefined,
getAutoLinkedIssuesOrPullRequests(commit.message, remotes),
getAutoLinkedIssuesOrPullRequests(message, remotes),
options?.pullRequests?.pr ??
getPullRequestForCommit(commit.ref, remotes, {
pullRequests:
@ -232,7 +239,7 @@ export namespace Hovers {
'pullRequestState',
),
}),
Container.instance.vsls.maybeGetPresence(commit.email),
Container.instance.vsls.maybeGetPresence(commit.author.email),
]);
if (options?.cancellationToken?.isCancellationRequested) return new MarkdownString();
@ -284,14 +291,14 @@ export namespace Hovers {
!Container.instance.config.hovers.autolinks.enhanced ||
!CommitFormatter.has(Container.instance.config.hovers.detailsMarkdownFormat, 'message')
) {
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}
const remote = await Container.instance.git.getRichRemoteProvider(remotes);
if (remote?.provider == null) {
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}
@ -306,15 +313,15 @@ export namespace Hovers {
if (autolinks != null && Logger.enabled(LogLevel.Debug)) {
// If there are any issues/PRs that timed out, log it
const count = Iterables.count(autolinks.values(), pr => pr instanceof PromiseCancelledError);
if (count !== 0) {
const prCount = count(autolinks.values(), pr => pr instanceof PromiseCancelledError);
if (prCount !== 0) {
Logger.debug(
cc,
`timed out ${
GlyphChars.Dash
} ${count} issue/pull request queries took too long (over ${timeout} ms) ${
} ${prCount} issue/pull request queries took too long (over ${timeout} ms) ${
GlyphChars.Dot
} ${Strings.getDurationMilliseconds(start)} ms`,
} ${getDurationMilliseconds(start)} ms`,
);
// const pending = [
@ -336,11 +343,11 @@ export namespace Hovers {
}
}
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return autolinks;
} catch (ex) {
Logger.error(ex, cc, `failed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.error(ex, cc, `failed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}
@ -359,14 +366,14 @@ export namespace Hovers {
const start = hrtime();
if (!options?.pullRequests) {
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}
const remote = await Container.instance.git.getRichRemoteProvider(remotes, { includeDisconnected: true });
if (remote?.provider == null) {
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}
@ -374,7 +381,7 @@ export namespace Hovers {
const { provider } = remote;
const connected = provider.maybeConnected ?? (await provider.isConnected());
if (!connected) {
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return remote;
}
@ -382,17 +389,17 @@ export namespace Hovers {
try {
const pr = await Container.instance.git.getPullRequestForCommit(ref, provider, { timeout: 250 });
Logger.debug(cc, `completed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `completed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return pr;
} catch (ex) {
if (ex instanceof PromiseCancelledError) {
Logger.debug(cc, `timed out ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.debug(cc, `timed out ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return ex;
}
Logger.error(ex, cc, `failed ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`);
Logger.error(ex, cc, `failed ${GlyphChars.Dot} ${getDurationMilliseconds(start)} ms`);
return undefined;
}

+ 17
- 17
src/hovers/lineHoverController.ts Datei anzeigen

@ -116,22 +116,22 @@ export class LineHoverController implements Disposable {
);
if (!wholeLine && range.start.character !== position.character) return undefined;
// Get the full commit message -- since blame only returns the summary
let logCommit = lineState?.logCommit;
if (logCommit == null && !commit.isUncommitted) {
logCommit = await this.container.git.getCommitForFile(commit.repoPath, commit.uri, {
ref: commit.sha,
});
if (logCommit != null) {
// Preserve the previous commit from the blame commit
logCommit.previousSha = commit.previousSha;
logCommit.previousFileName = commit.previousFileName;
if (lineState != null) {
lineState.logCommit = logCommit;
}
}
}
// // Get the full commit message -- since blame only returns the summary
// let logCommit = lineState?.logCommit;
// if (logCommit == null && !commit.isUncommitted) {
// logCommit = await this.container.git.getCommitForFile(commit.repoPath, commit.uri, {
// ref: commit.sha,
// });
// if (logCommit != null) {
// // Preserve the previous commit from the blame commit
// logCommit.previousSha = commit.previousSha;
// logCommit.previousFileName = commit.previousFileName;
// if (lineState != null) {
// lineState.logCommit = logCommit;
// }
// }
// }
let editorLine = position.line;
const line = editorLine + 1;
@ -142,7 +142,7 @@ export class LineHoverController implements Disposable {
if (trackedDocument == null) return undefined;
const message = await Hovers.detailsMessage(
logCommit ?? commit,
commit,
trackedDocument.uri,
editorLine,
this.container.config.hovers.detailsMarkdownFormat,

+ 5
- 3
src/messages.ts Datei anzeigen

@ -1,6 +1,6 @@
import { ConfigurationTarget, env, MessageItem, Uri, window } from 'vscode';
import { configuration } from './configuration';
import { GitCommit } from './git/models';
import { GitCommit, GitCommit2 } from './git/models';
import { Logger } from './logger';
export const enum SuppressedMessages {
@ -18,7 +18,9 @@ export const enum SuppressedMessages {
}
export class Messages {
static showCommitHasNoPreviousCommitWarningMessage(commit?: GitCommit): Promise<MessageItem | undefined> {
static showCommitHasNoPreviousCommitWarningMessage(
commit?: GitCommit | GitCommit2,
): Promise<MessageItem | undefined> {
if (commit === undefined) {
return Messages.showMessage(
'info',
@ -28,7 +30,7 @@ export class Messages {
}
return Messages.showMessage(
'info',
`Commit ${commit.shortSha} (${commit.author}, ${commit.formattedDate}) has no previous commit.`,
`Commit ${commit.shortSha} (${commit.author.name}, ${commit.formattedDate}) has no previous commit.`,
SuppressedMessages.CommitHasNoPreviousCommitWarning,
);
}

+ 42
- 26
src/premium/github/github.ts Datei anzeigen

@ -524,7 +524,11 @@ export class GitHubApi {
email
name
}
committer { date }
committer {
date
email
name
}
}
}
}
@ -645,20 +649,24 @@ export class GitHubApi {
const result = rsp?.data;
if (result == null) return undefined;
const { commit } = result;
return {
oid: result.sha,
parents: { nodes: result.parents.map(p => ({ oid: p.sha })) },
message: result.commit.message,
message: commit.message,
additions: result.stats?.additions,
changedFiles: result.files?.length,
deletions: result.stats?.deletions,
author: {
date: result.commit.author?.date ?? result.commit.committer?.date ?? new Date().toString(),
email: result.commit.author?.email ?? undefined,
name: result.commit.author?.name ?? '',
avatarUrl: result.author?.avatar_url ?? undefined,
date: commit.author?.date ?? new Date().toString(),
email: commit.author?.email ?? undefined,
name: commit.author?.name ?? '',
},
committer: {
date: result.commit.committer?.date ?? result.commit.author?.date ?? new Date().toString(),
date: commit.committer?.date ?? new Date().toString(),
email: commit.committer?.email ?? undefined,
name: commit.committer?.name ?? '',
},
files: result.files,
};
@ -720,11 +728,16 @@ export class GitHubApi {
changedFiles
deletions
author {
avatarUrl
date
email
name
}
committer {
date
email
name
}
committer { date }
}
}
}
@ -783,23 +796,28 @@ export class GitHubApi {
endCursor
hasNextPage
}
nodes { ... on Commit { ...commit } }
nodes {
... on Commit {
oid
message
parents(first: 3) { nodes { oid } }
author {
avatarUrl
date
email
name
}
committer {
date
email
name
}
}
}
}
}
}
}
}
fragment commit on Commit {
oid
message
parents(first: 100) { nodes { oid } }
author {
date
email
name
}
committer { date }
}`;
const rsp = await this.graphql<QueryResult>(token, query, {
@ -1195,6 +1213,8 @@ export interface GitHubBlameRange {
};
committer: {
date: string;
email: string;
name: string;
};
};
}
@ -1216,12 +1236,8 @@ export interface GitHubCommit {
additions: number | undefined;
changedFiles: number | undefined;
deletions: number | undefined;
author: {
date: string;
email: string | undefined;
name: string;
};
committer: { date: string };
author: { avatarUrl: string | undefined; date: string; email: string | undefined; name: string };
committer: { date: string; email: string | undefined; name: string };
files?: Endpoints['GET /repos/{owner}/{repo}/commits/{ref}']['response']['data']['files'];
}

+ 27
- 25
src/premium/github/githubGitProvider.ts Datei anzeigen

@ -36,11 +36,12 @@ import {
BranchSortOptions,
GitAuthor,
GitBlame,
GitBlameCommit,
GitBlameLine,
GitBlameLines,
GitBranch,
GitBranchReference,
GitCommit2,
GitCommitIdentity,
GitCommitLine,
GitCommitType,
GitContributor,
@ -49,6 +50,7 @@ import {
GitDiffHunkLine,
GitDiffShortStat,
GitFile,
GitFileChange,
GitFileIndexStatus,
GitLog,
GitLogCommit,
@ -376,7 +378,8 @@ export class GitHubGitProvider implements GitProvider, Disposable {
if (context == null) return undefined;
const { metadata, github, remotehub, session } = context;
const file = this.getRelativePath(uri, remotehub.getProviderRootUri(uri));
const root = remotehub.getVirtualUri(remotehub.getProviderRootUri(uri));
const file = this.getRelativePath(uri, root);
// const sha = await this.resolveReferenceCore(uri.repoPath!, metadata, uri.sha);
// if (sha == null) return undefined;
@ -391,17 +394,19 @@ export class GitHubGitProvider implements GitProvider, Disposable {
);
const authors = new Map<string, GitAuthor>();
const commits = new Map<string, GitBlameCommit>();
const commits = new Map<string, GitCommit2>();
const lines: GitCommitLine[] = [];
for (const range of blame.ranges) {
const c = range.commit;
const { viewer = session.account.label } = blame;
const name = viewer != null && range.commit.author.name === viewer ? 'You' : range.commit.author.name;
const name = viewer != null && c.author.name === viewer ? 'You' : c.author.name;
let author = authors.get(rangeclass="p">.commit.author.name);
let author = authors.get(c.author.name);
if (author == null) {
author = {
name: range.commit.author.name,
name: c.author.name,
lineCount: 0,
};
authors.set(name, author);
@ -409,29 +414,26 @@ export class GitHubGitProvider implements GitProvider, Disposable {
author.lineCount += range.endingLine - range.startingLine + 1;
let commit = commits.get(rangeclass="p">.commit.oid);
let commit = commits.get(c.oid);
if (commit == null) {
commit = new GitBlameCommit(
commit = new GitCommit2(
uri.repoPath!,
range.commit.oid,
author.name,
range.commit.author.email,
new Date(range.commit.author.date),
new Date(range.commit.committer.date),
range.commit.message,
file,
undefined,
range.commit.parents.nodes[0]?.oid,
undefined,
c.oid,
new GitCommitIdentity(author.name, c.author.email, new Date(c.author.date), c.author.avatarUrl),
new GitCommitIdentity(c.committer.name, c.committer.email, new Date(c.author.date)),
c.message.split('\n', 1)[0],
c.parents.nodes[0]?.oid ? [c.parents.nodes[0]?.oid] : [],
c.message,
new GitFileChange(root.toString(), file, GitFileIndexStatus.Modified),
[],
);
commits.set(rangeclass="p">.commit.oid, commit);
commits.set(c.oid, commit);
}
for (let i = range.startingLine; i <= range.endingLine; i++) {
const line: GitCommitLine = {
sha: range.commit.oid,
sha: c.oid,
line: i,
originalLine: i,
};
@ -495,7 +497,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
const commit = blame.commits.get(blameLine.sha);
if (commit == null) return undefined;
const author = blame.authors.get(commit.author)!;
const author = blame.authors.get(commit.author.name)!;
return {
author: { ...author, lineCount: commit.lines.length },
commit: commit,
@ -545,7 +547,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
const endLine = range.end.line + 1;
const authors = new Map<string, GitAuthor>();
const commits = new Map<string, GitBlameCommit>();
const commits = new Map<string, GitCommit2>();
for (const c of blame.commits.values()) {
if (!shas.has(c.sha)) continue;
@ -554,10 +556,10 @@ export class GitHubGitProvider implements GitProvider, Disposable {
});
commits.set(c.sha, commit);
let author = authors.get(commit.author);
let author = authors.get(commit.author.name);
if (author == null) {
author = {
name: commit.author,
name: commit.author.name,
lineCount: 0,
};
authors.set(author.name, author);
@ -1234,7 +1236,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
return undefined;
}
authors.set(c.author, log.authors.get(c.author)!);
authors.set(c.author.name, log.authors.get(c.author.name)!);
return [ref, c];
},
),

+ 2
- 2
src/quickpicks/gitQuickPickItems.ts Datei anzeigen

@ -188,7 +188,7 @@ export namespace CommitQuickPickItem {
if (options.compact) {
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
description: `${commit.author}, ${commit.formattedDate}${pad('$(git-commit)', 2, 2)}${
description: `${commit.author.name}, ${commit.formattedDate}${pad('$(git-commit)', 2, 2)}${
commit.shortSha
}${pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({ compact: true })}`,
alwaysShow: options.alwaysShow,
@ -202,7 +202,7 @@ export namespace CommitQuickPickItem {
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
description: '',
detail: `${GlyphChars.Space.repeat(2)}${commit.author}, ${commit.formattedDate}${pad(
detail: `${GlyphChars.Space.repeat(2)}${commit.author.name}, ${commit.formattedDate}${pad(
'$(git-commit)',
2,
2,

+ 5
- 5
src/statusbar/statusBarController.ts Datei anzeigen

@ -15,7 +15,7 @@ import { configuration, FileAnnotationType, StatusBarCommand } from '../configur
import { GlyphChars, isTextEditor } from '../constants';
import { Container } from '../container';
import { CommitFormatter } from '../git/formatters';
import { GitBlameCommit, PullRequest } from '../git/models';
import { GitCommit2, PullRequest } from '../git/models';
import { Hovers } from '../hovers/hovers';
import { LogCorrelationContext, Logger } from '../logger';
import { debug } from '../system/decorators/log';
@ -172,7 +172,7 @@ export class StatusBarController implements Disposable {
}
@debug({ args: false })
private async updateBlame(editor: TextEditor, commit: GitBlameCommit, options?: { pr?: PullRequest | null }) {
private async updateBlame(editor: TextEditor, commit: GitCommit2, options?: { pr?: PullRequest | null }) {
const cfg = this.container.config.statusBar;
if (!cfg.enabled || this._statusBarBlame == null || !isTextEditor(editor)) return;
@ -332,7 +332,7 @@ export class StatusBarController implements Disposable {
}
private async getPullRequest(
commit: GitBlameCommit,
commit: GitCommit2,
{ timeout }: { timeout?: number } = {},
): Promise<PullRequest | PromiseCancelledError<Promise<PullRequest | undefined>> | undefined> {
const remote = await this.container.git.getRichRemoteProvider(commit.repoPath);
@ -348,7 +348,7 @@ export class StatusBarController implements Disposable {
private async updateCommitTooltip(
statusBarItem: StatusBarItem,
commit: GitBlameCommit,
commit: GitCommit2,
actionTooltip: string,
getBranchAndTagTips:
| ((
@ -386,7 +386,7 @@ export class StatusBarController implements Disposable {
private async waitForPendingPullRequest(
editor: TextEditor,
commit: GitBlameCommit,
commit: GitCommit2,
pr: PullRequest | PromiseCancelledError<Promise<PullRequest | undefined>> | undefined,
cancellationToken: CancellationToken,
timeout: number,

+ 13
- 13
src/system/string.ts Datei anzeigen

@ -137,6 +137,19 @@ export function getDurationMilliseconds(start: [number, number]) {
return secs * 1000 + Math.floor(nanosecs / 1000000);
}
export function* getLines(s: string, char: string = '\n'): IterableIterator<string> {
let i = 0;
while (i < s.length) {
let j = s.indexOf(char, i);
if (j === -1) {
j = s.length;
}
yield s.substring(i, j);
i = j + 1;
}
}
const superscripts = ['\u00B9', '\u00B2', '\u00B3', '\u2074', '\u2075', '\u2076', '\u2077', '\u2078', '\u2079'];
export function getSuperscript(num: number) {
@ -249,19 +262,6 @@ export function isUpperAsciiLetter(code: number): boolean {
return code >= CharCode.A && code <= CharCode.Z;
}
export function* lines(s: string, char: string = '\n'): IterableIterator<string> {
let i = 0;
while (i < s.length) {
let j = s.indexOf(char, i);
if (j === -1) {
j = s.length;
}
yield s.substring(i, j);
i = j + 1;
}
}
export function md5(s: string, encoding: 'base64' | 'hex' = 'base64'): string {
return _md5(s, encoding);
}

+ 2
- 2
src/trackers/gitLineTracker.ts Datei anzeigen

@ -1,7 +1,7 @@
import { Disposable, TextEditor } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitBlameCommit, GitLogCommit } from '../git/models';
import { GitCommit2, GitLogCommit } from '../git/models';
import { Logger } from '../logger';
import { debug } from '../system';
import {
@ -16,7 +16,7 @@ import { LinesChangeEvent, LineSelection, LineTracker } from './lineTracker';
export * from './lineTracker';
export class GitLineState {
constructor(public readonly commit: GitBlameCommit | undefined, public logCommit?: GitLogCommit) {}
constructor(public readonly commit: GitCommit2 | undefined, public logCommit?: GitLogCommit) {}
}
export class GitLineTracker extends LineTracker<GitLineState> {

+ 2
- 2
src/views/nodes/commitFileNode.ts Datei anzeigen

@ -129,8 +129,8 @@ export class CommitFileNode
override getCommand(): Command | undefined {
let line;
if (this.commit.line !== undefined) {
line = this.commit.line.to.line - 1;
if (this.commit.lines.length) {
line = this.commit.lines[0].to.line - 1;
} else {
line = this._options.selection !== undefined ? this._options.selection.active.line : 0;
}

+ 2
- 2
src/views/nodes/fileRevisionAsCommitNode.ts Datei anzeigen

@ -145,8 +145,8 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
override getCommand(): Command | undefined {
let line;
if (this.commit.line !== undefined) {
line = this.commit.line.to.line - 1;
if (this.commit.lines.length) {
line = this.commit.lines[0].to.line - 1;
} else {
line = this._options.selection !== undefined ? this._options.selection.active.line : 0;
}

+ 23
- 23
src/views/nodes/lineHistoryNode.ts Datei anzeigen

@ -109,9 +109,9 @@ export class LineHistoryNode
const file: GitFile = {
conflictStatus: status?.conflictStatus,
fileName: commit.fileName,
fileName: commit.file?.path ?? '',
indexStatus: status?.indexStatus,
originalFileName: commit.originalFileName,
originalFileName: commit.file?.originalPath,
repoPath: this.uri.repoPath!,
status: status?.status ?? GitFileIndexStatus.Modified,
workingTreeStatus: status?.workingTreeStatus,
@ -123,16 +123,16 @@ export class LineHistoryNode
this.uri.repoPath!,
GitRevision.uncommittedStaged,
'You',
commit.email,
commit.authorDate,
commit.committerDate,
commit.message,
commit.fileName,
commit.author.email,
commit.author.date,
commit.committer.date,
commit.message ?? commit.summary,
file.fileName,
[file],
GitFileIndexStatus.Modified,
commit.originalFileName,
file.originalFileName,
commit.previousSha,
commit.originalFileName ?? commit.fileName,
file.originalFileName ?? file.fileName,
);
children.splice(
@ -148,16 +148,16 @@ export class LineHistoryNode
this.uri.repoPath!,
GitRevision.uncommitted,
'You',
commit.email,
commit.authorDate,
commit.committerDate,
commit.message,
commit.fileName,
commit.author.email,
commit.author.date,
commit.committer.date,
commit.message ?? commit.summary,
file.fileName,
[file],
GitFileIndexStatus.Modified,
commit.originalFileName,
file.originalFileName,
GitRevision.uncommittedStaged,
commit.originalFileName ?? commit.fileName,
file.originalFileName ?? file.fileName,
);
children.splice(
@ -177,16 +177,16 @@ export class LineHistoryNode
? GitRevision.uncommittedStaged
: commit.sha,
'You',
commit.email,
commit.authorDate,
commit.committerDate,
commit.message,
commit.fileName,
commit.author.email,
commit.author.date,
commit.committer.date,
commit.message ?? commit.summary,
file.fileName,
[file],
GitFileIndexStatus.Modified,
commit.originalFileName,
file.originalFileName,
commit.previousSha,
commit.originalFileName ?? commit.fileName,
file.originalFileName ?? file.fileName,
);
children.splice(

+ 12
- 10
src/webviews/rebaseEditor.ts Datei anzeigen

@ -537,19 +537,20 @@ async function parseRebaseTodo(
const ontoCommit = onto ? foundCommits.find(c => c.ref.startsWith(onto)) : undefined;
if (ontoCommit != null) {
if (!authors.has(ontoCommit.author)) {
authors.set(ontoCommit.author, {
author: ontoCommit.author,
const { name, email } = ontoCommit.author;
if (!authors.has(name)) {
authors.set(name, {
author: name,
avatarUrl: (
await ontoCommit.getAvatarUri({ defaultStyle: container.config.defaultGravatarsStyle })
).toString(true),
email: ontoCommit.email,
email: email,
});
}
commits.push({
ref: ontoCommit.ref,
author: ontoCommit.author,
author: name,
date: ontoCommit.formatDate(container.config.defaultDateFormat),
dateFromNow: ontoCommit.formatDateFromNow(),
message: ontoCommit.message || 'root',
@ -566,19 +567,20 @@ async function parseRebaseTodo(
onto = '';
}
if (!authors.has(commit.author)) {
authors.set(commit.author, {
author: commit.author,
const { name, email } = commit.author;
if (!authors.has(name)) {
authors.set(name, {
author: name,
avatarUrl: (
await commit.getAvatarUri({ defaultStyle: container.config.defaultGravatarsStyle })
).toString(true),
email: commit.email,
email: email,
});
}
commits.push({
ref: commit.ref,
author: commit.author,
author: name,
date: commit.formatDate(container.config.defaultDateFormat),
dateFromNow: commit.formatDateFromNow(),
message: commit.message,

+ 18
- 10
src/webviews/webviewBase.ts Datei anzeigen

@ -16,7 +16,14 @@ import { Commands } from '../commands';
import { configuration } from '../configuration';
import { Container } from '../container';
import { CommitFormatter } from '../git/formatters';
import { GitBlameCommit, PullRequest, PullRequestState } from '../git/models';
import {
GitCommit2,
GitCommitIdentity,
GitFileChange,
GitFileIndexStatus,
PullRequest,
PullRequestState,
} from '../git/models';
import { Logger } from '../logger';
import {
DidChangeConfigurationNotificationType,
@ -195,18 +202,19 @@ export abstract class WebviewBase implements Disposable {
onIpcCommand(PreviewConfigurationCommandType, e, async params => {
switch (params.type) {
case 'commit': {
const commit = new GitBlameCommit(
const commit = new GitCommit2(
'~/code/eamodio/vscode-gitlens-demo',
'fe26af408293cba5b4bfd77306e1ac9ff7ccaef8',
'You',
'eamodio@gmail.com',
new Date('2016-11-12T20:41:00.000Z'),
new Date('2020-11-01T06:57:21.000Z'),
new GitCommitIdentity('You', 'eamodio@gmail.com', new Date('2016-11-12T20:41:00.000Z')),
new GitCommitIdentity('You', 'eamodio@gmail.com', new Date('2020-11-01T06:57:21.000Z')),
'Supercharged',
['3ac1d3f51d7cf5f438cc69f25f6740536ad80fef'],
'Supercharged',
'code.ts',
undefined,
'3ac1d3f51d7cf5f438cc69f25f6740536ad80fef',
'code.ts',
new GitFileChange(
'~/code/eamodio/vscode-gitlens-demo',
'code.ts',
GitFileIndexStatus.Modified,
),
[],
);

Laden…
Abbrechen
Speichern