Browse Source

Renames/reworks git models for files and statuses

main
Eric Amodio 6 years ago
parent
commit
52a549e85b
27 changed files with 350 additions and 360 deletions
  1. +3
    -3
      src/commands/diffWithBranch.ts
  2. +1
    -1
      src/commands/externalDiff.ts
  3. +27
    -16
      src/git/formatters/statusFormatter.ts
  4. +6
    -5
      src/git/gitService.ts
  5. +19
    -23
      src/git/gitUri.ts
  6. +98
    -0
      src/git/models/file.ts
  7. +22
    -22
      src/git/models/logCommit.ts
  8. +1
    -0
      src/git/models/models.ts
  9. +7
    -7
      src/git/models/stashCommit.ts
  10. +15
    -111
      src/git/models/status.ts
  11. +18
    -17
      src/git/parsers/diffParser.ts
  12. +14
    -14
      src/git/parsers/logParser.ts
  13. +10
    -10
      src/git/parsers/stashParser.ts
  14. +3
    -3
      src/git/parsers/statusParser.ts
  15. +13
    -15
      src/quickpicks/commitQuickPick.ts
  16. +14
    -18
      src/quickpicks/repoStatusQuickPick.ts
  17. +5
    -5
      src/views/explorerCommands.ts
  18. +9
    -10
      src/views/nodes/commitFileNode.ts
  19. +1
    -1
      src/views/nodes/commitNode.ts
  20. +4
    -4
      src/views/nodes/fileHistoryNode.ts
  21. +6
    -10
      src/views/nodes/lineHistoryNode.ts
  22. +2
    -2
      src/views/nodes/resultsFilesNode.ts
  23. +3
    -3
      src/views/nodes/stashFileNode.ts
  24. +5
    -5
      src/views/nodes/stashNode.ts
  25. +11
    -16
      src/views/nodes/statusFileCommitsNode.ts
  26. +8
    -14
      src/views/nodes/statusFileNode.ts
  27. +25
    -25
      src/views/nodes/statusFilesNode.ts

+ 3
- 3
src/commands/diffWithBranch.ts View File

@ -60,10 +60,10 @@ export class DiffWithBranchCommand extends ActiveEditorCommand {
let renamedTitle: string | undefined;
// Check to see if this file has been renamed
const statuses = await Container.git.getDiffStatus(gitUri.repoPath, 'HEAD', ref, { filter: 'R' });
if (statuses !== undefined) {
const files = await Container.git.getDiffStatus(gitUri.repoPath, 'HEAD', ref, { filter: 'R' });
if (files !== undefined) {
const fileName = Strings.normalizePath(path.relative(gitUri.repoPath, gitUri.fsPath));
const rename = statuses.find(s => s.fileName === fileName);
const rename = files.find(s => s.fileName === fileName);
if (rename !== undefined && rename.originalFileName !== undefined) {
renamedUri = Uri.file(path.join(gitUri.repoPath, rename.originalFileName));
renamedTitle = `${path.basename(rename.originalFileName)} (${ref})`;

+ 1
- 1
src/commands/externalDiff.ts View File

@ -122,7 +122,7 @@ export class ExternalDiffCommand extends Command {
args.files.push(new ExternalDiffFile(file.uri, true));
}
if (file.workTreeStatus === 'M') {
if (file.workingTreeStatus === 'M') {
args.files.push(new ExternalDiffFile(file.uri, false));
}
}

+ 27
- 16
src/git/formatters/statusFormatter.ts View File

@ -2,7 +2,7 @@
import * as path from 'path';
import { GlyphChars } from '../../constants';
import { Strings } from '../../system';
import { GitStatusFile, IGitStatusFile, IGitStatusFileWithCommit } from '../models/status';
import { GitFile, GitFileWithCommit } from '../models/file';
import { Formatter, IFormatOptions } from './formatter';
export interface IStatusFormatOptions extends IFormatOptions {
@ -18,9 +18,9 @@ export interface IStatusFormatOptions extends IFormatOptions {
};
}
export class StatusFileFormatter extends Formatter<IGitStatusFile, IStatusFormatOptions> {
export class StatusFileFormatter extends Formatter<GitFile, IStatusFormatOptions> {
get directory() {
const directory = GitStatusFile.getFormattedDirectory(this._item, false, this._options.relativePath);
const directory = GitFile.getFormattedDirectory(this._item, false, this._options.relativePath);
return this._padOrTruncate(directory, this._options.tokenOptions!.directory);
}
@ -30,40 +30,51 @@ export class StatusFileFormatter extends Formatter
}
get filePath() {
const filePath = GitStatusFile.getFormattedPath(this._item, { relativeTo: this._options.relativePath });
const filePath = GitFile.getFormattedPath(this._item, { relativeTo: this._options.relativePath });
return this._padOrTruncate(filePath, this._options.tokenOptions!.filePath);
}
get path() {
const directory = GitStatusFile.getRelativePath(this._item, this._options.relativePath);
const directory = GitFile.getRelativePath(this._item, this._options.relativePath);
return this._padOrTruncate(directory, this._options.tokenOptions!.path);
}
get status() {
const status = GitStatusFile.getStatusText(this._item.status);
const status = GitFile.getStatusText(this._item.status);
return this._padOrTruncate(status, this._options.tokenOptions!.status);
}
get working() {
const commit = (this._item as IGitStatusFileWithCommit).commit;
return this._padOrTruncate(
commit !== undefined && commit.isUncommitted ? GlyphChars.Pencil : '',
this._options.tokenOptions!.working
);
const commit = (this._item as GitFileWithCommit).commit;
const statusFile = commit === undefined ? this._item : commit.files[0];
let icon = '';
if (statusFile.workingTreeStatus !== undefined && statusFile.indexStatus !== undefined) {
icon = `${GlyphChars.Pencil}${GlyphChars.Space}${GlyphChars.Check}`;
}
else {
if (statusFile.workingTreeStatus !== undefined) {
icon = `${GlyphChars.Pencil}${GlyphChars.Space.repeat(4)}`;
}
else if (statusFile.indexStatus !== undefined) {
icon = `${GlyphChars.Space.repeat(5)}${GlyphChars.Check}`;
}
}
return this._padOrTruncate(icon, this._options.tokenOptions!.working);
}
static fromTemplate(template: string, status: IGitStatusFile, dateFormat: string | null): string;
static fromTemplate(template: string, status: IGitStatusFile, options?: IStatusFormatOptions): string;
static fromTemplate(template: string, file: GitFile, dateFormat: string | null): string;
static fromTemplate(template: string, file: GitFile, options?: IStatusFormatOptions): string;
static fromTemplate(
template: string,
status: IGitStatusFile,
file: GitFile,
dateFormatOrOptions?: string | null | IStatusFormatOptions
): string;
static fromTemplate(
template: string,
status: IGitStatusFile,
file: GitFile,
dateFormatOrOptions?: string | null | IStatusFormatOptions
): string {
return super.fromTemplateCore(this, template, status, dateFormatOrOptions);
return super.fromTemplateCore(this, template, file, dateFormatOrOptions);
}
}

+ 6
- 5
src/git/gitService.ts View File

@ -40,6 +40,7 @@ import {
GitDiffChunkLine,
GitDiffParser,
GitDiffShortStat,
GitFile,
GitLog,
GitLogCommit,
GitLogParser,
@ -493,15 +494,15 @@ export class GitService implements Disposable {
if (ref === undefined) return undefined;
}
// Get the full commit (so we can see if there are any matching renames in the file statuses)
// Get the full commit (so we can see if there are any matching renames in the files)
const log = await this.getLog(repoPath, { maxCount: 1, ref: ref });
if (log === undefined) return undefined;
const c = Iterables.first(log.commits.values());
const status = c.fileStatuses.find(f => f.originalFileName === fileName);
if (status === undefined) return undefined;
const file = c.files.find(f => f.originalFileName === fileName);
if (file === undefined) return undefined;
return status.fileName;
return file.fileName;
}
async findWorkingFileName(commit: GitCommit): Promise<[string | undefined, string | undefined]>;
@ -1088,7 +1089,7 @@ export class GitService implements Disposable {
ref1?: string,
ref2?: string,
options: { filter?: string } = {}
): Promise<GitStatusFile[] | undefined> {
): Promise<GitFile[] | undefined> {
Logger.log(`getDiffStatus('${repoPath}', '${ref1}', '${ref2}', ${options.filter})`);
try {

+ 19
- 23
src/git/gitUri.ts View File

@ -4,7 +4,7 @@ import { Uri } from 'vscode';
import { UriComparer } from '../comparers';
import { DocumentSchemes, GlyphChars } from '../constants';
import { Container } from '../container';
import { GitCommit, GitService, IGitStatusFile } from '../git/gitService';
import { GitCommit, GitFile, GitService } from '../git/gitService';
import { Strings } from '../system';
export interface GitCommitish {
@ -167,9 +167,9 @@ export class GitUri extends ((Uri as any) as UriEx) {
});
}
static fromFileStatus(status: IGitStatusFile, repoPath: string, sha?: string, original: boolean = false): GitUri {
const uri = Uri.file(path.resolve(repoPath, (original && status.originalFileName) || status.fileName));
return sha === undefined ? new GitUri(uri, repoPath) : new GitUri(uri, { repoPath: repoPath, sha: sha });
static fromFile(file: GitFile, repoPath: string, ref?: string, original: boolean = false): GitUri {
const uri = Uri.file(path.resolve(repoPath, (original && file.originalFileName) || file.fileName));
return ref === undefined ? new GitUri(uri, repoPath) : new GitUri(uri, { repoPath: repoPath, sha: ref });
}
static fromRepoPath(repoPath: string, ref?: string) {
@ -280,40 +280,36 @@ export class GitUri extends ((Uri as any) as UriEx) {
}
static toRevisionUri(uri: GitUri): Uri;
static toRevisionUri(sha: string, fileName: string, repoPath: string): Uri;
static toRevisionUri(sha: string, status: IGitStatusFile, repoPath: string): Uri;
static toRevisionUri(
uriOrSha: string | GitUri,
fileNameOrStatus?: string | IGitStatusFile,
repoPath?: string
): Uri {
static toRevisionUri(ref: string, fileName: string, repoPath: string): Uri;
static toRevisionUri(ref: string, file: GitFile, repoPath: string): Uri;
static toRevisionUri(uriOrRef: string | GitUri, fileNameOrFile?: string | GitFile, repoPath?: string): Uri {
let fileName: string;
let sha: string | undefined;
let ref: string | undefined;
let shortSha: string | undefined;
if (typeof uriOrSha === 'string') {
if (typeof fileNameOrStatus === 'string') {
fileName = fileNameOrStatus;
if (typeof uriOrRef === 'string') {
if (typeof fileNameOrFile === 'string') {
fileName = fileNameOrFile;
}
else {
fileName = path.resolve(repoPath!, fileNameOrStatus!.fileName);
fileName = path.resolve(repoPath!, fileNameOrFile!.fileName);
}
sha = uriOrSha;
shortSha = GitService.shortenSha(sha);
ref = uriOrRef;
shortSha = GitService.shortenSha(ref);
}
else {
fileName = uriOrSha.fsPath!;
repoPath = uriOrSha.repoPath!;
sha = uriOrSha.sha;
shortSha = uriOrSha.shortSha;
fileName = uriOrRef.fsPath!;
repoPath = uriOrRef.repoPath!;
ref = uriOrRef.sha;
shortSha = uriOrRef.shortSha;
}
repoPath = Strings.normalizePath(repoPath!);
const repoName = path.basename(repoPath);
const data: IUriRevisionData = {
path: Strings.normalizePath(fileName, { addLeadingSlash: true }),
ref: sha,
ref: ref,
repoPath: repoPath
};

+ 98
- 0
src/git/models/file.ts View File

@ -0,0 +1,98 @@
'use strict';
import { GlyphChars } from '../../constants';
import { Strings } from '../../system';
import { GitUri } from '../gitUri';
import { GitLogCommit } from './logCommit';
export declare type GitFileStatus = '!' | '?' | 'A' | 'C' | 'D' | 'M' | 'R' | 'T' | 'U' | 'X' | 'B';
export interface GitFile {
status: GitFileStatus;
readonly repoPath: string;
readonly indexStatus: GitFileStatus | undefined;
readonly workingTreeStatus: GitFileStatus | undefined;
readonly fileName: string;
readonly originalFileName?: string;
}
export interface GitFileWithCommit extends GitFile {
readonly commit: GitLogCommit;
}
export namespace GitFile {
export function getFormattedDirectory(
file: GitFile,
includeOriginal: boolean = false,
relativeTo?: string
): string {
const directory = GitUri.getDirectory(file.fileName, relativeTo);
return includeOriginal && file.status === 'R' && file.originalFileName
? `${directory} ${Strings.pad(GlyphChars.ArrowLeft, 1, 1)} ${file.originalFileName}`
: directory;
}
export function getFormattedPath(
file: GitFile,
options: { relativeTo?: string; separator?: string; suffix?: string } = {}
): string {
return GitUri.getFormattedPath(file.fileName, options);
}
export function getRelativePath(file: GitFile, relativeTo?: string): string {
return GitUri.getRelativePath(file.fileName, relativeTo);
}
const statusIconsMap = {
'!': 'icon-status-ignored.svg',
'?': 'icon-status-untracked.svg',
A: 'icon-status-added.svg',
C: 'icon-status-copied.svg',
D: 'icon-status-deleted.svg',
M: 'icon-status-modified.svg',
R: 'icon-status-renamed.svg',
T: 'icon-status-modified.svg',
U: 'icon-status-conflict.svg',
X: 'icon-status-unknown.svg',
B: 'icon-status-unknown.svg'
};
export function getStatusIcon(status: GitFileStatus): string {
return statusIconsMap[status] || statusIconsMap['X'];
}
const statusOcticonsMap = {
'!': '$(diff-ignored)',
'?': '$(diff-added)',
A: '$(diff-added)',
C: '$(diff-added)',
D: '$(diff-removed)',
M: '$(diff-modified)',
R: '$(diff-renamed)',
T: '$(diff-modified)',
U: '$(alert)',
X: '$(question)',
B: '$(question)'
};
export function getStatusOcticon(status: GitFileStatus, missing: string = GlyphChars.Space.repeat(4)): string {
return statusOcticonsMap[status] || missing;
}
const statusTextMap = {
'!': 'Ignored',
'?': 'Untracked',
A: 'Added',
C: 'Copied',
D: 'Deleted',
M: 'Modified',
R: 'Renamed',
T: 'Modified',
U: 'Conflict',
X: 'Unknown',
B: 'Unknown'
};
export function getStatusText(status: GitFileStatus): string {
return statusTextMap[status] || statusTextMap['X'];
}
}

+ 22
- 22
src/git/models/logCommit.ts View File

@ -4,7 +4,7 @@ import { Uri } from 'vscode';
import { Strings } from '../../system';
import { Git } from '../git';
import { GitCommit, GitCommitType } from './commit';
import { GitStatusFileStatus, IGitStatusFile } from './status';
import { GitFile, GitFileStatus } from './file';
export class GitLogCommit extends GitCommit {
nextSha?: string;
@ -19,8 +19,8 @@ export class GitLogCommit extends GitCommit {
date: Date,
message: string,
fileName: string,
public readonly fileStatuses: IGitStatusFile[],
public readonly status: GitStatusFileStatus | undefined,
public readonly files: GitFile[],
public readonly status: GitFileStatus | undefined,
originalFileName: string | undefined,
previousSha: string | undefined,
previousFileName: string | undefined,
@ -73,8 +73,8 @@ export class GitLogCommit extends GitCommit {
changed: 0
};
if (this.fileStatuses.length !== 0) {
for (const f of this.fileStatuses) {
if (this.files.length !== 0) {
for (const f of this.files) {
switch (f.status) {
case 'A':
case '?':
@ -128,21 +128,21 @@ export class GitLogCommit extends GitCommit {
}
toFileCommit(fileName: string): GitLogCommit | undefined;
toFileCommit(status: IGitStatusFile): GitLogCommit;
toFileCommit(fileNameOrStatus: string | IGitStatusFile): GitLogCommit | undefined {
let status: IGitStatusFile | undefined;
if (typeof fileNameOrStatus === 'string') {
const fileName = Strings.normalizePath(path.relative(this.repoPath, fileNameOrStatus));
status = this.fileStatuses.find(f => f.fileName === fileName);
if (status === undefined) return undefined;
toFileCommit(file: GitFile): GitLogCommit;
toFileCommit(fileNameOrFile: string | GitFile): GitLogCommit | undefined {
let file: GitFile | undefined;
if (typeof fileNameOrFile === 'string') {
const fileName = Strings.normalizePath(path.relative(this.repoPath, fileNameOrFile));
file = this.files.find(f => f.fileName === fileName);
if (file === undefined) return undefined;
}
else {
status = fileNameOrStatus;
file = fileNameOrFile;
}
let sha;
// If this is a stash commit with an untracked file
if (this.type === GitCommitType.Stash && status.status === '?') {
if (this.type === GitCommitType.Stash && file.status === '?') {
sha = `${this.sha}^3`;
}
@ -152,12 +152,12 @@ export class GitLogCommit extends GitCommit {
return this.with({
type: this.isStash ? GitCommitType.StashFile : GitCommitType.File,
sha: sha,
fileName: status.fileName,
originalFileName: status.originalFileName,
fileName: file.fileName,
originalFileName: file.originalFileName,
previousSha: previousSha,
previousFileName: status.originalFileName || status.fileName,
status: status.status,
fileStatuses: [status]
previousFileName: file.originalFileName || file.fileName,
status: file.status,
files: [file]
});
}
@ -172,8 +172,8 @@ export class GitLogCommit extends GitCommit {
originalFileName?: string | null;
previousFileName?: string | null;
previousSha?: string | null;
status?: GitStatusFileStatus;
fileStatuses?: IGitStatusFile[] | null;
status?: GitFileStatus;
files?: GitFile[] | null;
}): GitLogCommit {
return new GitLogCommit(
changes.type || this.type,
@ -184,7 +184,7 @@ export class GitLogCommit extends GitCommit {
changes.date || this.date,
changes.message || this.message,
changes.fileName || this.fileName,
this.getChangedValue(changes.fileStatuses, this.fileStatuses) || [],
this.getChangedValue(changes.files, this.files) || [],
changes.status || this.status,
this.getChangedValue(changes.originalFileName, this.originalFileName),
this.getChangedValue(changes.previousSha, this.previousSha),

+ 1
- 0
src/git/models/models.ts View File

@ -5,6 +5,7 @@ export * from './blameCommit';
export * from './branch';
export * from './commit';
export * from './diff';
export * from './file';
export * from './log';
export * from './logCommit';
export * from './remote';

+ 7
- 7
src/git/models/stashCommit.ts View File

@ -1,7 +1,7 @@
'use strict';
import { GitCommitType } from './commit';
import { GitFile, GitFileStatus } from './file';
import { GitLogCommit } from './logCommit';
import { GitStatusFileStatus, IGitStatusFile } from './status';
export class GitStashCommit extends GitLogCommit {
constructor(
@ -12,8 +12,8 @@ export class GitStashCommit extends GitLogCommit {
date: Date,
message: string,
fileName: string,
fileStatuses: IGitStatusFile[],
status?: GitStatusFileStatus | undefined,
files: GitFile[],
status?: GitFileStatus | undefined,
originalFileName?: string | undefined,
previousSha?: string | undefined,
previousFileName?: string | undefined
@ -27,7 +27,7 @@ export class GitStashCommit extends GitLogCommit {
date,
message,
fileName,
fileStatuses,
files,
status,
originalFileName,
previousSha === undefined ? `${sha}^` : previousSha,
@ -48,8 +48,8 @@ export class GitStashCommit extends GitLogCommit {
originalFileName?: string | null;
previousFileName?: string | null;
previousSha?: string | null;
status?: GitStatusFileStatus;
fileStatuses?: IGitStatusFile[] | null;
status?: GitFileStatus;
files?: GitFile[] | null;
}): GitLogCommit {
return new GitStashCommit(
changes.type || this.type,
@ -59,7 +59,7 @@ export class GitStashCommit extends GitLogCommit {
changes.date || this.date,
changes.message || this.message,
changes.fileName || this.fileName,
this.getChangedValue(changes.fileStatuses, this.fileStatuses) || [],
this.getChangedValue(changes.files, this.files) || [],
changes.status || this.status,
this.getChangedValue(changes.originalFileName, this.originalFileName),
this.getChangedValue(changes.previousSha, this.previousSha),

+ 15
- 111
src/git/models/status.ts View File

@ -3,9 +3,8 @@ import * as path from 'path';
import { Uri } from 'vscode';
import { GlyphChars } from '../../constants';
import { Strings } from '../../system';
import { GitUri } from '../gitUri';
import { GitBranch } from './branch';
import { GitLogCommit } from './logCommit';
import { GitFile, GitFileStatus } from './file';
export interface GitStatusUpstreamState {
ahead: number;
@ -136,32 +135,17 @@ export class GitStatus {
}
}
export declare type GitStatusFileStatus = '!' | '?' | 'A' | 'C' | 'D' | 'M' | 'R' | 'T' | 'U' | 'X' | 'B';
export interface IGitStatusFile {
status: GitStatusFileStatus;
readonly repoPath: string;
readonly indexStatus: GitStatusFileStatus;
readonly workTreeStatus: GitStatusFileStatus;
readonly fileName: string;
readonly originalFileName?: string;
}
export interface IGitStatusFileWithCommit extends IGitStatusFile {
readonly commit: GitLogCommit;
}
export class GitStatusFile implements IGitStatusFile {
export class GitStatusFile implements GitFile {
constructor(
public readonly repoPath: string,
public readonly indexStatus: GitStatusFileStatus,
public readonly workTreeStatus: GitStatusFileStatus,
public readonly indexStatus: GitFileStatus | undefined,
public readonly workingTreeStatus: GitFileStatus | undefined,
public readonly fileName: string,
public readonly originalFileName?: string
) {}
get status(): GitStatusFileStatus {
return (this.indexStatus || this.workTreeStatus || '?') as GitStatusFileStatus;
get status(): GitFileStatus {
return (this.indexStatus || this.workingTreeStatus || '?') as GitFileStatus;
}
get staged() {
@ -173,31 +157,31 @@ export class GitStatusFile implements IGitStatusFile {
}
getFormattedDirectory(includeOriginal: boolean = false): string {
return GitStatusFile.getFormattedDirectory(this, includeOriginal);
return GitFile.getFormattedDirectory(this, includeOriginal);
}
getFormattedPath(options: { relativeTo?: string; separator?: string; suffix?: string } = {}): string {
return GitStatusFile.getFormattedPath(this, options);
return GitFile.getFormattedPath(this, options);
}
getOcticon() {
return getGitStatusOcticon(this.status);
return GitFile.getStatusOcticon(this.status);
}
getStatusText(status: IGitStatusFile): string {
return GitStatusFile.getStatusText(this.status);
getStatusText(file: GitFile): string {
return GitFile.getStatusText(this.status);
}
with(changes: {
indexStatus?: GitStatusFileStatus | null;
workTreeStatus?: GitStatusFileStatus | null;
indexStatus?: GitFileStatus | null;
workTreeStatus?: GitFileStatus | null;
fileName?: string;
originalFileName?: string | null;
}): GitStatusFile {
return new GitStatusFile(
this.repoPath,
this.getChangedValue(changes.indexStatus, this.indexStatus) as GitStatusFileStatus,
this.getChangedValue(changes.workTreeStatus, this.workTreeStatus) as GitStatusFileStatus,
this.getChangedValue(changes.indexStatus, this.indexStatus) as GitFileStatus,
this.getChangedValue(changes.workTreeStatus, this.workingTreeStatus) as GitFileStatus,
changes.fileName || this.fileName,
this.getChangedValue(changes.originalFileName, this.originalFileName)
);
@ -207,84 +191,4 @@ export class GitStatusFile implements IGitStatusFile {
if (change === undefined) return original;
return change !== null ? change : undefined;
}
static getFormattedDirectory(
status: IGitStatusFile,
includeOriginal: boolean = false,
relativeTo?: string
): string {
const directory = GitUri.getDirectory(status.fileName, relativeTo);
return includeOriginal && status.status === 'R' && status.originalFileName
? `${directory} ${Strings.pad(GlyphChars.ArrowLeft, 1, 1)} ${status.originalFileName}`
: directory;
}
static getFormattedPath(
status: IGitStatusFile,
options: { relativeTo?: string; separator?: string; suffix?: string } = {}
): string {
return GitUri.getFormattedPath(status.fileName, options);
}
static getRelativePath(status: IGitStatusFile, relativeTo?: string): string {
return GitUri.getRelativePath(status.fileName, relativeTo);
}
static getStatusText(status: GitStatusFileStatus): string {
return getGitStatusText(status);
}
}
const statusOcticonsMap = {
'!': '$(diff-ignored)',
'?': '$(diff-added)',
A: '$(diff-added)',
C: '$(diff-added)',
D: '$(diff-removed)',
M: '$(diff-modified)',
R: '$(diff-renamed)',
T: '$(diff-modified)',
U: '$(alert)',
X: '$(question)',
B: '$(question)'
};
export function getGitStatusOcticon(status: GitStatusFileStatus, missing: string = GlyphChars.Space.repeat(4)): string {
return statusOcticonsMap[status] || missing;
}
const statusIconsMap = {
'!': 'icon-status-ignored.svg',
'?': 'icon-status-untracked.svg',
A: 'icon-status-added.svg',
C: 'icon-status-copied.svg',
D: 'icon-status-deleted.svg',
M: 'icon-status-modified.svg',
R: 'icon-status-renamed.svg',
T: 'icon-status-modified.svg',
U: 'icon-status-conflict.svg',
X: 'icon-status-unknown.svg',
B: 'icon-status-unknown.svg'
};
export function getGitStatusIcon(status: GitStatusFileStatus): string {
return statusIconsMap[status] || statusIconsMap['X'];
}
const statusTextMap = {
'!': 'ignored',
'?': 'untracked',
A: 'added',
C: 'copied',
D: 'deleted',
M: 'modified',
R: 'renamed',
T: 'modified',
U: 'conflict',
X: 'unknown',
B: 'unknown'
};
export function getGitStatusText(status: GitStatusFileStatus): string {
return statusTextMap[status] || statusTextMap['X'];
}

+ 18
- 17
src/git/parsers/diffParser.ts View File

@ -6,8 +6,8 @@ import {
GitDiffChunkLine,
GitDiffLine,
GitDiffShortStat,
GitStatusFile,
GitStatusParser
GitFile,
GitFileStatus
} from './../git';
const nameStatusDiffRegex = /^(.*?)\t(.*?)(?:\t(.*?))?$/gm;
@ -137,32 +137,33 @@ export class GitDiffParser {
return chunkLines;
}
static parseNameStatus(data: string, repoPath: string): GitStatusFile[] | undefined {
static parseNameStatus(data: string, repoPath: string): GitFile[] | undefined {
if (!data) return undefined;
const statuses: GitStatusFile[] = [];
const files: GitFile[] = [];
let match: RegExpExecArray | null = null;
do {
match = nameStatusDiffRegex.exec(data);
if (match == null) break;
statuses.push(
GitStatusParser.parseStatusFile(
repoPath,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + match[1]).substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
(' ' + match[2]).substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
match[3] === undefined ? undefined : (' ' + match[3]).substr(1)
)
);
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
const status = (' ' + match[1]).substr(1);
files.push({
repoPath,
status: (status[0] !== '.' ? status[0].trim() : '?') as GitFileStatus,
indexStatus: undefined,
workingTreeStatus: undefined,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
fileName: (' ' + match[2]).substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
originalFileName: match[3] === undefined ? undefined : (' ' + match[3]).substr(1)
} as GitFile);
} while (match != null);
if (!statuses.length) return undefined;
if (!files.length) return undefined;
return statuses;
return files;
}
static parseShortStat(data: string): GitDiffShortStat | undefined {

+ 14
- 14
src/git/parsers/logParser.ts View File

@ -2,7 +2,7 @@
import * as path from 'path';
import { Range } from 'vscode';
import { Arrays, Strings } from '../../system';
import { Git, GitAuthor, GitCommitType, GitLog, GitLogCommit, GitStatusFileStatus, IGitStatusFile } from './../git';
import { Git, GitAuthor, GitCommitType, GitFile, GitFileStatus, GitLog, GitLogCommit } from './../git';
interface LogEntry {
ref?: string;
@ -15,9 +15,9 @@ interface LogEntry {
fileName?: string;
originalFileName?: string;
fileStatuses?: IGitStatusFile[];
files?: GitFile[];
status?: GitStatusFileStatus;
status?: GitFileStatus;
summary?: string;
}
@ -140,17 +140,17 @@ export class GitLogParser {
if (type === GitCommitType.Branch) {
const status = {
status: line[0] as GitStatusFileStatus,
status: line[0] as GitFileStatus,
fileName: line.substring(1),
originalFileName: undefined
} as IGitStatusFile;
} as GitFile;
this.parseFileName(status);
if (status.fileName) {
if (entry.fileStatuses === undefined) {
entry.fileStatuses = [];
if (entry.files === undefined) {
entry.files = [];
}
entry.fileStatuses.push(status);
entry.files.push(status);
}
}
else if (line.startsWith('diff')) {
@ -174,15 +174,15 @@ export class GitLogParser {
break;
}
else {
entry.status = line[0] as GitStatusFileStatus;
entry.status = line[0] as GitFileStatus;
entry.fileName = line.substring(1);
this.parseFileName(entry);
}
}
if (entry.fileStatuses !== undefined) {
if (entry.files !== undefined) {
entry.fileName = Arrays.filterMap(
entry.fileStatuses,
entry.files,
f => (!!f.fileName ? f.fileName : undefined)
).join(', ');
}
@ -268,12 +268,12 @@ export class GitLogParser {
const originalFileName = relativeFileName !== entry.fileName ? entry.fileName : undefined;
if (type === GitCommitType.File) {
entry.fileStatuses = [
entry.files = [
{
status: entry.status,
fileName: relativeFileName,
originalFileName: originalFileName
} as IGitStatusFile
} as GitFile
];
}
@ -286,7 +286,7 @@ export class GitLogParser {
new Date((entry.date! as any) * 1000),
entry.summary === undefined ? '' : entry.summary,
relativeFileName,
entry.fileStatuses || [],
entry.files || [],
entry.status,
originalFileName,
undefined,

+ 10
- 10
src/git/parsers/stashParser.ts View File

@ -1,13 +1,13 @@
'use strict';
import { Arrays, Strings } from '../../system';
import { GitCommitType, GitLogParser, GitStash, GitStashCommit, GitStatusFileStatus, IGitStatusFile } from './../git';
import { GitCommitType, GitFile, GitFileStatus, GitLogParser, GitStash, GitStashCommit } from './../git';
// import { Logger } from './logger';
interface StashEntry {
ref?: string;
date?: string;
fileNames?: string;
fileStatuses?: IGitStatusFile[];
files?: GitFile[];
summary?: string;
stashName?: string;
}
@ -94,23 +94,23 @@ export class GitStashParser {
if (line.startsWith('warning:')) continue;
const status = {
status: line[0] as GitStatusFileStatus,
status: line[0] as GitFileStatus,
fileName: line.substring(1),
originalFileName: undefined
} as IGitStatusFile;
} as GitFile;
GitLogParser.parseFileName(status);
if (status.fileName) {
if (entry.fileStatuses === undefined) {
entry.fileStatuses = [];
if (entry.files === undefined) {
entry.files = [];
}
entry.fileStatuses.push(status);
entry.files.push(status);
}
}
if (entry.fileStatuses !== undefined) {
if (entry.files !== undefined) {
entry.fileNames = Arrays.filterMap(
entry.fileStatuses,
entry.files,
f => (!!f.fileName ? f.fileName : undefined)
).join(', ');
}
@ -142,7 +142,7 @@ export class GitStashParser {
new Date((entry.date! as any) * 1000),
entry.summary === undefined ? '' : entry.summary,
entry.fileNames!,
entry.fileStatuses || []
entry.files || []
);
}

+ 3
- 3
src/git/parsers/statusParser.ts View File

@ -1,6 +1,6 @@
'use strict';
import { Strings } from '../../system';
import { GitStatus, GitStatusFile, GitStatusFileStatus } from './../git';
import { GitFileStatus, GitStatus, GitStatusFile } from './../git';
const aheadStatusV1Regex = /(?:ahead ([0-9]+))/;
const behindStatusV1Regex = /(?:behind ([0-9]+))/;
@ -138,8 +138,8 @@ export class GitStatusParser {
return new GitStatusFile(
repoPath,
indexStatus as GitStatusFileStatus,
workTreeStatus as GitStatusFileStatus,
indexStatus as GitFileStatus | undefined,
workTreeStatus as GitFileStatus | undefined,
fileName,
originalFileName
);

+ 13
- 15
src/quickpicks/commitQuickPick.ts View File

@ -14,14 +14,12 @@ import {
import { GlyphChars } from '../constants';
import { Container } from '../container';
import {
getGitStatusOcticon,
GitFile,
GitFileStatus,
GitLog,
GitLogCommit,
GitStashCommit,
GitStatusFile,
GitStatusFileStatus,
GitUri,
IGitStatusFile,
RemoteResource
} from '../git/gitService';
import { KeyCommand, KeyNoopCommand, Keys } from '../keyboard';
@ -38,21 +36,21 @@ import {
import { OpenRemotesCommandQuickPickItem } from './remotesQuickPick';
export class CommitWithFileStatusQuickPickItem extends OpenFileCommandQuickPickItem {
readonly status: GitStatusFileStatus;
readonly status: GitFileStatus;
readonly commit: GitLogCommit;
constructor(commit: GitLogCommit, status: IGitStatusFile) {
const octicon = getGitStatusOcticon(status.status);
const description = GitStatusFile.getFormattedDirectory(status, true);
constructor(commit: GitLogCommit, file: GitFile) {
const octicon = GitFile.getStatusOcticon(file.status);
const description = GitFile.getFormattedDirectory(file, true);
super(GitUri.toRevisionUri(commit.sha, status, commit.repoPath), {
label: `${Strings.pad(octicon, 4, 2)} ${path.basename(status.fileName)}`,
super(GitUri.toRevisionUri(commit.sha, file, commit.repoPath), {
label: `${Strings.pad(octicon, 4, 2)} ${path.basename(file.fileName)}`,
description: description
});
this.commit = commit.toFileCommit(status);
this.status = status.status;
this.commit = commit.toFileCommit(file);
this.status = file.status;
}
get sha(): string {
@ -75,7 +73,7 @@ export class CommitWithFileStatusQuickPickItem extends OpenFileCommandQuickPickI
export class OpenCommitFilesCommandQuickPickItem extends OpenFilesCommandQuickPickItem {
constructor(commit: GitLogCommit, versioned: boolean = false, item?: QuickPickItem) {
const repoPath = commit.repoPath;
const uris = Arrays.filterMap(commit.fileStatuses, f => GitUri.fromFileStatus(f, repoPath));
const uris = Arrays.filterMap(commit.files, f => GitUri.fromFile(f, repoPath));
super(
uris,
@ -90,7 +88,7 @@ export class OpenCommitFilesCommandQuickPickItem extends OpenFilesCommandQuickPi
export class OpenCommitFileRevisionsCommandQuickPickItem extends OpenFilesCommandQuickPickItem {
constructor(commit: GitLogCommit, item?: QuickPickItem) {
const uris = Arrays.filterMap(commit.fileStatuses, f =>
const uris = Arrays.filterMap(commit.files, f =>
GitUri.toRevisionUri(f.status === 'D' ? commit.previousFileSha : commit.sha, f, commit.repoPath)
);
@ -117,7 +115,7 @@ export class CommitQuickPick {
): Promise<CommitWithFileStatusQuickPickItem | CommandQuickPickItem | undefined> {
await commit.resolvePreviousFileSha();
const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.fileStatuses.map(
const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.files.map(
fs => new CommitWithFileStatusQuickPickItem(commit, fs)
);

+ 14
- 18
src/quickpicks/repoStatusQuickPick.ts View File

@ -13,11 +13,11 @@ import { GlyphChars } from '../constants';
import { Container } from '../container';
import {
GitCommitType,
GitFileStatus,
GitLogCommit,
GitService,
GitStatus,
GitStatusFile,
GitStatusFileStatus,
GitUri
} from '../git/gitService';
import { Keys } from '../keyboard';
@ -33,7 +33,7 @@ export class OpenStatusFileCommandQuickPickItem extends OpenFileCommandQuickPick
public readonly status: GitStatusFile;
private readonly commit: GitLogCommit;
constructor(status: GitStatusFile, realIndexStatus?: GitStatusFileStatus, item?: QuickPickItem) {
constructor(status: GitStatusFile, realIndexStatus?: GitFileStatus, item?: QuickPickItem) {
const octicon = status.getOcticon();
const description = status.getFormattedDirectory(true);
@ -87,24 +87,20 @@ export class OpenStatusFileCommandQuickPickItem extends OpenFileCommandQuickPick
}
onDidPressKey(key: Keys): Promise<{} | undefined> {
return commands.executeCommand(
Commands.DiffWithPrevious,
GitUri.fromFileStatus(this.status, this.status.repoPath),
{
commit: this.commit,
line: 0,
showOptions: {
preserveFocus: true,
preview: false
} as TextDocumentShowOptions
} as DiffWithPreviousCommandArgs
) as Promise<{} | undefined>;
return commands.executeCommand(Commands.DiffWithPrevious, GitUri.fromFile(this.status, this.status.repoPath), {
commit: this.commit,
line: 0,
showOptions: {
preserveFocus: true,
preview: false
} as TextDocumentShowOptions
} as DiffWithPreviousCommandArgs) as Promise<{} | undefined>;
}
}
export class OpenStatusFilesCommandQuickPickItem extends CommandQuickPickItem {
constructor(statuses: GitStatusFile[], item?: QuickPickItem) {
const uris = statuses.map(f => f.uri);
constructor(files: GitStatusFile[], item?: QuickPickItem) {
const uris = files.map(f => f.uri);
super(
item || {
@ -166,7 +162,7 @@ export class RepoStatusQuickPick {
break;
}
switch (f.workTreeStatus) {
switch (f.workingTreeStatus) {
case 'A':
case '?':
unstagedAdds++;
@ -208,7 +204,7 @@ export class RepoStatusQuickPick {
> {
const items = [
...Iterables.flatMap(status.files, s => {
if (s.workTreeStatus !== undefined && s.indexStatus !== undefined) {
if (s.workingTreeStatus !== undefined && s.indexStatus !== undefined) {
return [
new OpenStatusFileCommandQuickPickItem(s.with({ indexStatus: null }), s.indexStatus),
new OpenStatusFileCommandQuickPickItem(s.with({ workTreeStatus: null }))

+ 5
- 5
src/views/explorerCommands.ts View File

@ -281,7 +281,7 @@ export class ExplorerCommands implements Disposable {
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
) {
const repoPath = node.commit.repoPath;
const uris = node.commit.fileStatuses.map(s => GitUri.fromFileStatus(s, repoPath));
const uris = node.commit.files.map(s => GitUri.fromFile(s, repoPath));
for (const uri of uris) {
await this.openDiffWith(
@ -303,8 +303,8 @@ export class ExplorerCommands implements Disposable {
) {
const repoPath = node.commit.repoPath;
const uris = Arrays.filterMap(
node.commit.fileStatuses,
f => (f.status !== 'D' ? GitUri.fromFileStatus(f, repoPath) : undefined)
node.commit.files,
f => (f.status !== 'D' ? GitUri.fromFile(f, repoPath) : undefined)
);
for (const uri of uris) {
@ -317,7 +317,7 @@ export class ExplorerCommands implements Disposable {
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
) {
const repoPath = node.commit.repoPath;
const uris = Arrays.filterMap(node.commit.fileStatuses, f => GitUri.fromFileStatus(f, repoPath));
const uris = Arrays.filterMap(node.commit.files, f => GitUri.fromFile(f, repoPath));
for (const uri of uris) {
await openEditor(uri, options);
@ -328,7 +328,7 @@ export class ExplorerCommands implements Disposable {
node: CommitNode | StashNode,
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
) {
const uris = Arrays.filterMap(node.commit.fileStatuses, f =>
const uris = Arrays.filterMap(node.commit.files, f =>
GitUri.toRevisionUri(
f.status === 'D' ? node.commit.previousFileSha : node.commit.sha,
f,

+ 9
- 10
src/views/nodes/commitFileNode.ts View File

@ -6,11 +6,10 @@ import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import {
CommitFormatter,
getGitStatusIcon,
GitFile,
GitLogCommit,
GitUri,
ICommitFormatOptions,
IGitStatusFile,
IStatusFormatOptions,
StatusFileFormatter
} from '../../git/gitService';
@ -32,14 +31,14 @@ export class CommitFileNode extends ExplorerRefNode {
readonly priority: boolean = false;
constructor(
public readonly status: IGitStatusFile,
public readonly file: GitFile,
public commit: GitLogCommit,
parent: ExplorerNode,
public readonly explorer: Explorer,
private readonly _displayAs: CommitFileNodeDisplayAs,
private readonly _selection?: Selection
) {
super(GitUri.fromFileStatus(status, commit.repoPath, commit.sha), parent);
super(GitUri.fromFile(file, commit.repoPath, commit.sha), parent);
}
get ref(): string {
@ -53,9 +52,9 @@ export class CommitFileNode extends ExplorerRefNode {
async getTreeItem(): Promise<TreeItem> {
if (!this.commit.isFile) {
// See if we can get the commit directly from the multi-file commit
const commit = this.commit.toFileCommit(this.status);
const commit = this.commit.toFileCommit(this.file);
if (commit === undefined) {
const log = await Container.git.getLogForFile(this.repoPath, this.status.fileName, {
const log = await Container.git.getLogForFile(this.repoPath, this.file.fileName, {
maxCount: 2,
ref: this.commit.sha
});
@ -79,7 +78,7 @@ export class CommitFileNode extends ExplorerRefNode {
};
}
else if ((this._displayAs & CommitFileNodeDisplayAs.StatusIcon) === CommitFileNodeDisplayAs.StatusIcon) {
const icon = getGitStatusIcon(this.status.status);
const icon = GitFile.getStatusIcon(this.file.status);
item.iconPath = {
dark: Container.context.asAbsolutePath(path.join('images', 'dark', icon)),
light: Container.context.asAbsolutePath(path.join('images', 'light', icon))
@ -115,7 +114,7 @@ export class CommitFileNode extends ExplorerRefNode {
truncateMessageAtNewLine: true,
dateFormat: Container.config.defaultDateFormat
} as ICommitFormatOptions)
: StatusFileFormatter.fromTemplate(this.getCommitFileTemplate(), this.status, {
: StatusFileFormatter.fromTemplate(this.getCommitFileTemplate(), this.file, {
relativePath: this.relativePath
} as IStatusFormatOptions);
}
@ -151,7 +150,7 @@ export class CommitFileNode extends ExplorerRefNode {
);
}
else {
this._tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this.status);
this._tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this.file);
}
}
return this._tooltip;
@ -170,7 +169,7 @@ export class CommitFileNode extends ExplorerRefNode {
title: 'Compare File with Previous Revision',
command: Commands.DiffWithPrevious,
arguments: [
GitUri.fromFileStatus(this.status, this.commit.repoPath),
GitUri.fromFile(this.file, this.commit.repoPath),
{
commit: this.commit,
line: this._selection !== undefined ? this._selection.active.line : 0,

+ 1
- 1
src/views/nodes/commitNode.ts View File

@ -31,7 +31,7 @@ export class CommitNode extends ExplorerRefNode {
const commit = this.commit;
let children: FileExplorerNode[] = [
...Iterables.map(
commit.fileStatuses,
commit.files,
s => new CommitFileNode(s, commit.toFileCommit(s), this, this.explorer, CommitFileNodeDisplayAs.File)
)
];

+ 4
- 4
src/views/nodes/fileHistoryNode.ts View File

@ -30,15 +30,15 @@ export class FileHistoryNode extends SubscribeableExplorerNode
(this.explorer.config.avatars ? CommitFileNodeDisplayAs.Gravatar : CommitFileNodeDisplayAs.StatusIcon);
const status = await Container.git.getStatusForFile(this.uri.repoPath!, this.uri.fsPath);
if (status !== undefined && (status.indexStatus !== undefined || status.workTreeStatus !== undefined)) {
if (status !== undefined && (status.indexStatus !== undefined || status.workingTreeStatus !== undefined)) {
let sha;
let previousSha;
if (status.workTreeStatus !== undefined) {
if (status.workingTreeStatus !== undefined) {
sha = GitService.uncommittedSha;
if (status.indexStatus !== undefined) {
previousSha = GitService.stagedUncommittedSha;
}
else if (status.workTreeStatus !== '?') {
else if (status.workingTreeStatus !== '?') {
previousSha = 'HEAD';
}
}
@ -71,7 +71,7 @@ export class FileHistoryNode extends SubscribeableExplorerNode
children.push(
...Iterables.map(
log.commits.values(),
c => new CommitFileNode(c.fileStatuses[0], c, this, this.explorer, displayAs)
c => new CommitFileNode(c.files[0], c, this, this.explorer, displayAs)
)
);
}

+ 6
- 10
src/views/nodes/lineHistoryNode.ts View File

@ -1,7 +1,7 @@
'use strict';
import { Disposable, Selection, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Container } from '../../container';
import { GitCommitType, GitLogCommit, IGitStatusFile } from '../../git/git';
import { GitCommitType, GitFile, GitLogCommit } from '../../git/git';
import {
GitService,
GitUri,
@ -41,7 +41,7 @@ export class LineHistoryNode extends SubscribeableExplorerNode
children.push(
...Iterables.filterMap(
log.commits.values(),
c => new CommitFileNode(c.fileStatuses[0], c, this, this.explorer, displayAs, this.selection)
c => new CommitFileNode(c.files[0], c, this, this.explorer, displayAs, this.selection)
)
);
}
@ -51,13 +51,13 @@ export class LineHistoryNode extends SubscribeableExplorerNode
const first = children[0] as CommitFileNode | undefined;
if (first === undefined || first.commit.sha !== blame.commit.sha) {
const status: IGitStatusFile = {
const file: GitFile = {
fileName: blame.commit.fileName,
indexStatus: '?',
originalFileName: blame.commit.originalFileName,
repoPath: this.uri.repoPath!,
status: 'M',
workTreeStatus: '?'
workingTreeStatus: '?'
};
const commit = new GitLogCommit(
@ -69,18 +69,14 @@ export class LineHistoryNode extends SubscribeableExplorerNode
blame.commit.date,
blame.commit.message,
blame.commit.fileName,
[status],
[file],
'M',
blame.commit.originalFileName,
blame.commit.previousSha,
blame.commit.originalFileName || blame.commit.fileName
);
children.splice(
0,
0,
new CommitFileNode(status, commit, this, this.explorer, displayAs, this.selection)
);
children.splice(0, 0, new CommitFileNode(file, commit, this, this.explorer, displayAs, this.selection));
}
}

+ 2
- 2
src/views/nodes/resultsFilesNode.ts View File

@ -3,7 +3,7 @@ import * as path from 'path';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { ExplorerFilesLayout } from '../../configuration';
import { Container } from '../../container';
import { GitStatusFile, GitUri } from '../../git/gitService';
import { GitFile, GitUri } from '../../git/gitService';
import { Arrays, Iterables, Strings } from '../../system';
import { Explorer } from '../explorer';
import { ExplorerNode, ResourceType } from './explorerNode';
@ -12,7 +12,7 @@ import { StatusFileNode } from './statusFileNode';
export interface FilesQueryResults {
label: string;
diff: GitStatusFile[] | undefined;
diff: GitFile[] | undefined;
}
export class ResultsFilesNode extends ExplorerNode {

+ 3
- 3
src/views/nodes/stashFileNode.ts View File

@ -1,12 +1,12 @@
'use strict';
import { GitLogCommit, IGitStatusFile } from '../../git/gitService';
import { GitFile, GitLogCommit } from '../../git/gitService';
import { Explorer } from '../explorer';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ExplorerNode, ResourceType } from './explorerNode';
export class StashFileNode extends CommitFileNode {
constructor(status: IGitStatusFile, commit: GitLogCommit, parent: ExplorerNode, explorer: Explorer) {
super(status, commit, parent, explorer, CommitFileNodeDisplayAs.File);
constructor(file: GitFile, commit: GitLogCommit, parent: ExplorerNode, explorer: Explorer) {
super(file, commit, parent, explorer, CommitFileNodeDisplayAs.File);
}
protected get resourceType(): ResourceType {

+ 5
- 5
src/views/nodes/stashNode.ts View File

@ -25,7 +25,7 @@ export class StashNode extends ExplorerRefNode {
}
async getChildren(): Promise<ExplorerNode[]> {
const statuses = (this.commit as GitStashCommit).fileStatuses;
const files = (this.commit as GitStashCommit).files;
// Check for any untracked files -- since git doesn't return them via `git stash list` :(
const log = await Container.git.getLog(this.commit.repoPath, {
@ -34,14 +34,14 @@ export class StashNode extends ExplorerRefNode {
});
if (log !== undefined) {
const commit = Iterables.first(log.commits.values());
if (commit !== undefined && commit.fileStatuses.length !== 0) {
if (commit !== undefined && commit.files.length !== 0) {
// Since these files are untracked -- make them look that way
commit.fileStatuses.forEach(s => (s.status = '?'));
statuses.splice(statuses.length, 0, ...commit.fileStatuses);
commit.files.forEach(s => (s.status = '?'));
files.splice(files.length, 0, ...commit.files);
}
}
const children = statuses.map(s => new StashFileNode(s, this.commit.toFileCommit(s), this, this.explorer));
const children = files.map(s => new StashFileNode(s, this.commit.toFileCommit(s), this, this.explorer));
children.sort((a, b) => a.label!.localeCompare(b.label!));
return children;
}

+ 11
- 16
src/views/nodes/statusFileCommitsNode.ts View File

@ -2,13 +2,11 @@
import * as path from 'path';
import { Command, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../../commands';
import { Container } from '../../container';
import {
getGitStatusIcon,
GitFile,
GitFileWithCommit,
GitLogCommit,
GitUri,
IGitStatusFile,
IGitStatusFileWithCommit,
IStatusFormatOptions,
StatusFileFormatter
} from '../../git/gitService';
@ -20,19 +18,19 @@ import { ExplorerNode, ResourceType } from './explorerNode';
export class StatusFileCommitsNode extends ExplorerNode {
constructor(
public readonly repoPath: string,
public readonly status: IGitStatusFile,
public readonly file: GitFile,
public readonly commits: GitLogCommit[],
parent: ExplorerNode,
public readonly explorer: Explorer
) {
super(GitUri.fromFileStatus(status, repoPath, 'HEAD'), parent);
super(GitUri.fromFile(file, repoPath, 'HEAD'), parent);
}
async getChildren(): Promise<ExplorerNode[]> {
return this.commits.map(
c =>
new CommitFileNode(
this.status,
this.file,
c,
this,
this.explorer,
@ -53,14 +51,12 @@ export class StatusFileCommitsNode extends ExplorerNode {
if (this.commit.isStagedUncommitted) {
item.tooltip = StatusFileFormatter.fromTemplate(
'${status} in index\n\n${file}\n${directory}/',
this.status
this.file
);
}
else {
item.tooltip = StatusFileFormatter.fromTemplate(
'${status} in working tree\n\n${file}\n${directory}/',
this.status
this.file
);
}
item.command = this.getCommand();
@ -68,8 +64,7 @@ export class StatusFileCommitsNode extends ExplorerNode {
else {
item.contextValue = ResourceType.StatusFileCommits;
item.tooltip = StatusFileFormatter.fromTemplate(
`\${status} in ${this.getChangedIn()}\n\n\${file}\n\${directory}/`,
this.status
this.file
);
}
@ -102,9 +97,9 @@ export class StatusFileCommitsNode extends ExplorerNode {
this._label = StatusFileFormatter.fromTemplate(
this.explorer.config.statusFileFormat,
{
...this.status,
...this.file,
commit: this.commit
} as IGitStatusFileWithCommit,
} as GitFileWithCommit,
{
relativePath: this.relativePath
} as IStatusFormatOptions
@ -163,7 +158,7 @@ export class StatusFileCommitsNode extends ExplorerNode {
title: 'Compare File with Previous Revision',
command: Commands.DiffWithPrevious,
arguments: [
GitUri.fromFileStatus(this.status, this.repoPath),
GitUri.fromFile(this.file, this.repoPath),
{
commit: this.commit,
line: 0,

+ 8
- 14
src/views/nodes/statusFileNode.ts View File

@ -3,26 +3,20 @@ import * as path from 'path';
import { Command, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Commands, DiffWithCommandArgs } from '../../commands';
import { Container } from '../../container';
import {
getGitStatusIcon,
GitStatusFile,
GitUri,
IStatusFormatOptions,
StatusFileFormatter
} from '../../git/gitService';
import { GitFile, GitStatusFile, GitUri, IStatusFormatOptions, StatusFileFormatter } from '../../git/gitService';
import { Explorer } from '../explorer';
import { ExplorerNode, ResourceType } from './explorerNode';
export class StatusFileNode extends ExplorerNode {
constructor(
public readonly repoPath: string,
private readonly _status: GitStatusFile,
private readonly _file: GitStatusFile,
private readonly _ref1: string,
private readonly _ref2: string,
parent: ExplorerNode,
public readonly explorer: Explorer
) {
super(GitUri.fromFileStatus(_status, repoPath, _ref1 ? _ref1 : _ref2 ? _ref2 : undefined), parent);
super(GitUri.fromFile(_file, repoPath, _ref1 ? _ref1 : _ref2 ? _ref2 : undefined), parent);
}
getChildren(): ExplorerNode[] {
@ -32,9 +26,9 @@ export class StatusFileNode extends ExplorerNode {
getTreeItem(): TreeItem {
const item = new TreeItem(this.label, TreeItemCollapsibleState.None);
item.contextValue = ResourceType.StatusFile;
item.tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this._status);
item.tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this._file);
const statusIcon = getGitStatusIcon(this._status.status);
const statusIcon = GitFile.getStatusIcon(this._file.status);
item.iconPath = {
dark: Container.context.asAbsolutePath(path.join('images', 'dark', statusIcon)),
light: Container.context.asAbsolutePath(path.join('images', 'light', statusIcon))
@ -55,7 +49,7 @@ export class StatusFileNode extends ExplorerNode {
private _label: string | undefined;
get label() {
if (this._label === undefined) {
this._label = StatusFileFormatter.fromTemplate(this.explorer.config.statusFileFormat, this._status, {
this._label = StatusFileFormatter.fromTemplate(this.explorer.config.statusFileFormat, this._file, {
relativePath: this.relativePath
} as IStatusFormatOptions);
}
@ -89,8 +83,8 @@ export class StatusFileNode extends ExplorerNode {
rhs: {
sha: this._ref2,
uri:
this._status.status === 'R'
? GitUri.fromFileStatus(this._status, this.uri.repoPath!, this._ref2, true)
this._file.status === 'R'
? GitUri.fromFile(this._file, this.uri.repoPath!, this._ref2, true)
: this.uri
},
repoPath: this.uri.repoPath!,

+ 25
- 25
src/views/nodes/statusFilesNode.ts View File

@ -6,12 +6,12 @@ import { Container } from '../../container';
import { GitStatusFile } from '../../git/git';
import {
GitCommitType,
GitFileWithCommit,
GitLog,
GitLogCommit,
GitService,
GitStatus,
GitUri,
IGitStatusFileWithCommit
GitUri
} from '../../git/gitService';
import { Arrays, Iterables, Objects, Strings } from '../../system';
import { RepositoriesExplorer } from '../repositoriesExplorer';
@ -37,7 +37,7 @@ export class StatusFilesNode extends ExplorerNode {
}
async getChildren(): Promise<ExplorerNode[]> {
let statuses: IGitStatusFileWithCommit[] = [];
let files: GitFileWithCommit[] = [];
const repoPath = this.repoPath;
@ -45,20 +45,20 @@ export class StatusFilesNode extends ExplorerNode {
if (this.range !== undefined) {
log = await Container.git.getLog(repoPath, { maxCount: 0, ref: this.range });
if (log !== undefined) {
statuses = [
files = [
...Iterables.flatMap(log.commits.values(), c =>
c.fileStatuses.map(s => ({ ...s, commit: c } as IGitStatusFileWithCommit))
c.files.map(s => ({ ...s, commit: c } as GitFileWithCommit))
)
];
}
}
if (this.status.files.length !== 0 && this.includeWorkingTree) {
statuses.splice(
files.splice(
0,
0,
...Iterables.flatMap(this.status.files, s => {
if (s.workTreeStatus !== undefined && s.indexStatus !== undefined) {
if (s.workingTreeStatus !== undefined && s.indexStatus !== undefined) {
// Decrements the date to guarantee this entry will be sorted after the previous entry (most recent first)
const older = new Date();
older.setMilliseconds(older.getMilliseconds() - 1);
@ -78,18 +78,18 @@ export class StatusFilesNode extends ExplorerNode {
);
}
statuses.sort((a, b) => b.commit.date.getTime() - a.commit.date.getTime());
files.sort((a, b) => b.commit.date.getTime() - a.commit.date.getTime());
const groups = Arrays.groupBy(statuses, s => s.fileName);
const groups = Arrays.groupBy(files, s => s.fileName);
let children: FileExplorerNode[] = [
...Iterables.map(
Objects.values(groups),
statuses =>
files =>
new StatusFileCommitsNode(
repoPath,
statuses[statuses.length - 1],
statuses.map(s => s.commit),
files[files.length - 1],
files.map(s => s.commit),
this,
this.explorer
)
@ -156,28 +156,28 @@ export class StatusFilesNode extends ExplorerNode {
return this.explorer.config.includeWorkingTree;
}
private toStatusFile(s: GitStatusFile, ref: string, previousRef: string, date?: Date): IGitStatusFileWithCommit {
private toStatusFile(file: GitStatusFile, ref: string, previousRef: string, date?: Date): GitFileWithCommit {
return {
status: s.status,
repoPath: s.repoPath,
indexStatus: s.indexStatus,
workTreeStatus: s.workTreeStatus,
fileName: s.fileName,
originalFileName: s.originalFileName,
status: file.status,
repoPath: file.repoPath,
indexStatus: file.indexStatus,
workingTreeStatus: file.workingTreeStatus,
fileName: file.fileName,
originalFileName: file.originalFileName,
commit: new GitLogCommit(
GitCommitType.File,
s.repoPath,
file.repoPath,
ref,
'You',
undefined,
date || new Date(),
'',
s.fileName,
[s],
s.status,
s.originalFileName,
file.fileName,
[file],
file.status,
file.originalFileName,
previousRef,
s.fileName
file.fileName
)
};
}

Loading…
Cancel
Save