diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88be184..d9c81f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]
### Added
+- Adds new file layouts to the `GitLens` custom view
+ - `auto` - automatically switches between displaying files as a `tree` or `list` based on the `gitlens.gitExplorer.files.threshold` setting and the number of files at each nesting level
+ - `list` - displays files as a list
+ - `tree` - displays files as a tree
+- Adds `gitlens.gitExplorer.files.layout` setting to specify how the `GitLens` custom view will display files
+- Adds `gitlens.gitExplorer.files.compact` setting to specify whether or not to compact (flatten) unnecessary file nesting in the `GitLens` custom view
+- Adds `gitlens.gitExplorer.files.threshold` setting to specify when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the `GitLens` custom view
- Adds `${directory}` token to the file formatting settings
### Changed
diff --git a/README.md b/README.md
index b2324dc..219ff2f 100644
--- a/README.md
+++ b/README.md
@@ -356,6 +356,9 @@ GitLens is highly customizable and provides many configuration settings to allow
|-----|------------
|`gitlens.gitExplorer.enabled`|Specifies whether or not to show the `GitLens` custom view"
|`gitlens.gitExplorer.view`|Specifies the starting view (mode) of the `GitLens` custom view
`auto` - shows the last selected view, defaults to `repository`
`history` - shows the commit history of the active file
`repository` - shows a repository explorer"
+|`gitlens.gitExplorer.files.layout`|Specifies how the `GitLens` custom view will display files
`auto` - automatically switches between displaying files as a `tree` or `list` based on the `gitlens.gitExplorer.files.threshold` setting and the number of files at each nesting level
`list` - displays files as a list
`tree` - displays files as a tree
+|`gitlens.gitExplorer.files.compact`|Specifies whether or not to compact (flatten) unnecessary file nesting in the `GitLens` custom view
Only applies when displaying files as a `tree` or `auto`
+|`gitlens.gitExplorer.files.threshold`|Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the `GitLens` custom view
Only applies when displaying files as `auto`
|`gitlens.gitExplorer.includeWorkingTree`|Specifies whether or not to include working tree files inside the `Repository Status` node of the `GitLens` custom view
|`gitlens.gitExplorer.showTrackingBranch`|Specifies whether or not to show the tracking branch when displaying local branches in the `GitLens` custom view"
|`gitlens.gitExplorer.commitFormat`|Specifies the format of committed changes in the `GitLens` custom view
Available tokens
${id} - commit id
${author} - commit author
${message} - commit message
${ago} - relative commit date (e.g. 1 day ago)
${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)
${authorAgo} - commit author, relative commit date
See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
diff --git a/package.json b/package.json
index b055007..5834e36 100644
--- a/package.json
+++ b/package.json
@@ -428,6 +428,26 @@
"default": true,
"description": "Specifies whether or not to show the `GitLens` custom view"
},
+ "gitlens.gitExplorer.files.layout": {
+ "type": "string",
+ "default": "auto",
+ "enum": [
+ "auto",
+ "list",
+ "tree"
+ ],
+ "description": "Specifies how the `GitLens` custom view will display files\n `auto` - automatically switches between displaying files as a `tree` or `list` based on the `gitlens.gitExplorer.files.threshold` setting and the number of files at each nesting level\n `list` - displays files as a list\n `tree` - displays files as a tree"
+ },
+ "gitlens.gitExplorer.files.compact": {
+ "type": "boolean",
+ "default": true,
+ "description": "Specifies whether or not to compact (flatten) unnecessary file nesting in the `GitLens` custom view\nOnly applies when displaying files as a `tree` or `auto`"
+ },
+ "gitlens.gitExplorer.files.threshold": {
+ "type": "number",
+ "default": 5,
+ "description": "Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the `GitLens` custom view\nOnly applies when displaying files as `auto`"
+ },
"gitlens.gitExplorer.includeWorkingTree": {
"type": "boolean",
"default": true,
diff --git a/src/configuration.ts b/src/configuration.ts
index 7de453f..15a9eb4 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -53,6 +53,16 @@ export const CustomRemoteType = {
GitLab: 'GitLab' as CustomRemoteType
};
+export type GitExplorerFilesLayout =
+ 'auto' |
+ 'list' |
+ 'tree';
+export const GitExplorerFilesLayout = {
+ Auto: 'auto' as GitExplorerFilesLayout,
+ List: 'list' as GitExplorerFilesLayout,
+ Tree: 'tree' as GitExplorerFilesLayout
+};
+
export type StatusBarCommand =
'gitlens.toggleFileBlame' |
'gitlens.showBlameHistory' |
@@ -132,6 +142,24 @@ export interface ICodeLensLanguageLocation {
customSymbols?: string[];
}
+export interface IGitExplorerConfig {
+ enabled: boolean;
+ view: GitExplorerView;
+ files: {
+ layout: GitExplorerFilesLayout;
+ compact: boolean;
+ threshold: number;
+ };
+ includeWorkingTree: boolean;
+ showTrackingBranch: boolean;
+ commitFormat: string;
+ commitFileFormat: string;
+ stashFormat: string;
+ stashFileFormat: string;
+ statusFileFormat: string;
+ // dateFormat: string | null;
+}
+
export interface IRemotesConfig {
type: CustomRemoteType;
domain: string;
@@ -316,18 +344,7 @@ export interface IConfig {
defaultDateFormat: string | null;
- gitExplorer: {
- enabled: boolean;
- view: GitExplorerView;
- includeWorkingTree: boolean;
- showTrackingBranch: boolean;
- commitFormat: string;
- commitFileFormat: string;
- stashFormat: string;
- stashFileFormat: string;
- statusFileFormat: string;
- // dateFormat: string | null;
- };
+ gitExplorer: IGitExplorerConfig;
remotes: IRemotesConfig[];
diff --git a/src/system/array.ts b/src/system/array.ts
index 13afa42..b314b4c 100644
--- a/src/system/array.ts
+++ b/src/system/array.ts
@@ -1,6 +1,16 @@
'use strict';
+import { Objects } from './object';
export namespace Arrays {
+ export function countUniques(array: T[], accessor: (item: T) => string): { [key: string]: number } {
+ const uniqueCounts = Object.create(null);
+ for (const item of array) {
+ const value = accessor(item);
+ uniqueCounts[value] = (uniqueCounts[value] || 0) + 1;
+ }
+ return uniqueCounts;
+ }
+
export function groupBy(array: T[], accessor: (item: T) => string): { [key: string]: T[] } {
return array.reduce((previous, current) => {
const value = accessor(current);
@@ -10,6 +20,96 @@ export namespace Arrays {
}, Object.create(null));
}
+ export interface IHierarchicalItem {
+ name: string;
+ relativePath: string;
+ value?: T;
+
+ // parent?: IHierarchicalItem;
+ children: { [key: string]: IHierarchicalItem } | undefined;
+ descendants: T[] | undefined;
+ }
+
+ export function makeHierarchical(values: T[], splitPath: (i: T) => string[], joinPath: (...paths: string[]) => string, compact: boolean = false): IHierarchicalItem {
+ const seed = {
+ name: '',
+ relativePath: '',
+ children: Object.create(null),
+ descendants: []
+ };
+
+ const hierarchy = values.reduce((root: IHierarchicalItem, value) => {
+ let folder = root;
+
+ let relativePath = '';
+ for (const folderName of splitPath(value)) {
+ relativePath = joinPath(relativePath, folderName);
+
+ if (folder.children === undefined) {
+ folder.children = Object.create(null);
+ }
+
+ let f = folder.children![folderName];
+ if (f === undefined) {
+ folder.children![folderName] = f = {
+ name: folderName,
+ relativePath: relativePath,
+ // parent: folder,
+ children: undefined,
+ descendants: undefined
+ };
+ }
+
+ if (folder.descendants === undefined) {
+ folder.descendants = [];
+ }
+ folder.descendants.push(value);
+ folder = f;
+ }
+
+ folder.value = value;
+
+ return root;
+ }, seed);
+
+ if (compact) return compactHierarchy(hierarchy, joinPath, true);
+ return hierarchy;
+ }
+
+ export function compactHierarchy(root: IHierarchicalItem, joinPath: (...paths: string[]) => string, isRoot: boolean = true): IHierarchicalItem {
+ if (root.children === undefined) return root;
+
+ const children = [...Objects.values(root.children)];
+
+ // // Attempts less nesting but duplicate roots
+ // if (!isRoot && children.every(c => c.value === undefined)) {
+ // const parentSiblings = root.parent!.children!;
+ // if (parentSiblings[root.name] !== undefined) {
+ // delete parentSiblings[root.name];
+
+ // for (const child of children) {
+ // child.name = joinPath(root.name, child.name);
+ // parentSiblings[child.name] = child;
+ // }
+ // }
+ // }
+
+ for (const child of children) {
+ compactHierarchy(child, joinPath, false);
+ }
+
+ if (!isRoot && children.length === 1) {
+ const child = children[0];
+ if (child.value === undefined) {
+ root.name = joinPath(root.name, child.name);
+ root.relativePath = child.relativePath;
+ root.children = child.children;
+ }
+ }
+
+ return root;
+ }
+
export function uniqueBy(array: T[], accessor: (item: T) => any, predicate?: (item: T) => boolean): T[] {
const uniqueValues = Object.create(null);
return array.filter(_ => {
diff --git a/src/views/commitFileNode.ts b/src/views/commitFileNode.ts
index 431ae9b..35542a3 100644
--- a/src/views/commitFileNode.ts
+++ b/src/views/commitFileNode.ts
@@ -2,7 +2,7 @@
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { ExplorerNode, ResourceType } from './explorerNode';
-import { CommitFormatter, getGitStatusIcon, GitBranch, GitCommit, GitService, GitUri, ICommitFormatOptions, IGitStatusFile, StatusFileFormatter } from '../gitService';
+import { CommitFormatter, getGitStatusIcon, GitBranch, GitCommit, GitService, GitUri, ICommitFormatOptions, IGitStatusFile, IStatusFormatOptions, StatusFileFormatter } from '../gitService';
import * as path from 'path';
export enum CommitFileNodeDisplayAs {
@@ -17,6 +17,8 @@ export enum CommitFileNodeDisplayAs {
export class CommitFileNode extends ExplorerNode {
+ readonly priority: boolean = false;
+ readonly repoPath: string;
readonly resourceType: ResourceType = 'gitlens:commit-file';
constructor(
@@ -28,6 +30,7 @@ export class CommitFileNode extends ExplorerNode {
public readonly branch?: GitBranch
) {
super(new GitUri(Uri.file(path.resolve(commit.repoPath, status.fileName)), { repoPath: commit.repoPath, fileName: status.fileName, sha: commit.sha }));
+ this.repoPath = commit.repoPath;
}
async getChildren(): Promise {
@@ -36,7 +39,7 @@ export class CommitFileNode extends ExplorerNode {
async getTreeItem(): Promise {
if (this.commit.type !== 'file') {
- const log = await this.git.getLogForFile(this.commit.repoPath, this.status.fileName, this.commit.sha, { maxCount: 2 });
+ const log = await this.git.getLogForFile(this.repoPath, this.status.fileName, this.commit.sha, { maxCount: 2 });
if (log !== undefined) {
this.commit = log.commits.get(this.commit.sha) || this.commit;
}
@@ -62,6 +65,14 @@ export class CommitFileNode extends ExplorerNode {
return item;
}
+ private _folderName: string | undefined;
+ get folderName() {
+ if (this._folderName === undefined) {
+ this._folderName = path.dirname(this.uri.getRelativePath());
+ }
+ return this._folderName;
+ }
+
private _label: string | undefined;
get label() {
if (this._label === undefined) {
@@ -70,11 +81,22 @@ export class CommitFileNode extends ExplorerNode {
truncateMessageAtNewLine: true,
dataFormat: this.git.config.defaultDateFormat
} as ICommitFormatOptions)
- : StatusFileFormatter.fromTemplate(this.getCommitFileTemplate(), this.status);
+ : StatusFileFormatter.fromTemplate(this.getCommitFileTemplate(),
+ this.status,
+ { relativePath: this.relativePath } as IStatusFormatOptions);
}
return this._label;
}
+ private _relativePath: string | undefined;
+ get relativePath(): string | undefined {
+ return this._relativePath;
+ }
+ set relativePath(value: string | undefined) {
+ this._relativePath = value;
+ this._label = undefined;
+ }
+
protected getCommitTemplate() {
return this.git.config.gitExplorer.commitFormat;
}
diff --git a/src/views/commitNode.ts b/src/views/commitNode.ts
index 17718e5..38c0aa9 100644
--- a/src/views/commitNode.ts
+++ b/src/views/commitNode.ts
@@ -1,13 +1,17 @@
'use strict';
-import { Iterables } from '../system';
+import { Arrays, Iterables } from '../system';
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
+import { GitExplorerFilesLayout } from '../configuration';
+import { FolderNode, IFileExplorerNode } from './folderNode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { CommitFormatter, GitBranch, GitLogCommit, GitService, GitUri, ICommitFormatOptions } from '../gitService';
+import * as path from 'path';
export class CommitNode extends ExplorerNode {
+ readonly repoPath: string;
readonly resourceType: ResourceType = 'gitlens:commit';
constructor(
@@ -17,17 +21,32 @@ export class CommitNode extends ExplorerNode {
public readonly branch?: GitBranch
) {
super(new GitUri(commit.uri, commit));
+ this.repoPath = commit.repoPath;
}
async getChildren(): Promise {
- const log = await this.git.getLogForRepo(this.commit.repoPath, this.commit.sha, 1);
+ const repoPath = this.repoPath;
+
+ const log = await this.git.getLogForRepo(repoPath, this.commit.sha, 1);
if (log === undefined) return [];
const commit = Iterables.first(log.commits.values());
if (commit === undefined) return [];
- const children = [...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git, CommitFileNodeDisplayAs.File, this.branch))];
- children.sort((a, b) => a.label!.localeCompare(b.label!));
+ let children: IFileExplorerNode[] = [
+ ...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git, CommitFileNodeDisplayAs.File, this.branch))
+ ];
+
+ if (this.git.config.gitExplorer.files.layout !== GitExplorerFilesLayout.List) {
+ const hierarchy = Arrays.makeHierarchical(children, n => n.uri.getRelativePath().split('/'),
+ (...paths: string[]) => GitService.normalizePath(path.join(...paths)), this.git.config.gitExplorer.files.compact);
+
+ const root = new FolderNode(repoPath, '', undefined, hierarchy, this.git.config.gitExplorer);
+ children = await root.getChildren() as IFileExplorerNode[];
+ }
+ else {
+ children.sort((a, b) => a.label!.localeCompare(b.label!));
+ }
return children;
}
diff --git a/src/views/explorerNode.ts b/src/views/explorerNode.ts
index 3c71eff..36f6521 100644
--- a/src/views/explorerNode.ts
+++ b/src/views/explorerNode.ts
@@ -10,6 +10,7 @@ export declare type ResourceType =
'gitlens:commit' |
'gitlens:commit-file' |
'gitlens:file-history' |
+ 'gitlens:folder' |
'gitlens:history' |
'gitlens:message' |
'gitlens:pager' |
diff --git a/src/views/folderNode.ts b/src/views/folderNode.ts
new file mode 100644
index 0000000..be2648f
--- /dev/null
+++ b/src/views/folderNode.ts
@@ -0,0 +1,85 @@
+'use strict';
+import { Arrays, Objects } from '../system';
+import { TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
+import { GitExplorerFilesLayout, IGitExplorerConfig } from '../configuration';
+import { ExplorerNode, ResourceType } from './explorerNode';
+import { GitUri } from '../gitService';
+
+export interface IFileExplorerNode extends ExplorerNode {
+ folderName: string;
+ label?: string;
+ priority: boolean;
+ relativePath?: string;
+ root?: Arrays.IHierarchicalItem;
+}
+
+export class FolderNode extends ExplorerNode {
+
+ readonly priority: boolean = true;
+ readonly resourceType: ResourceType = 'gitlens:folder';
+
+ constructor(
+ public readonly repoPath: string,
+ public folderName: string,
+ public relativePath: string | undefined,
+ public readonly root: Arrays.IHierarchicalItem,
+ private readonly config: IGitExplorerConfig
+ ) {
+ super(new GitUri(Uri.file(repoPath), { repoPath: repoPath, fileName: repoPath }));
+ }
+
+ async getChildren(): Promise<(FolderNode | IFileExplorerNode)[]> {
+ if (this.root.descendants === undefined || this.root.children === undefined) return [];
+
+ let children: (FolderNode | IFileExplorerNode)[];
+
+ const nesting = FolderNode.getFileNesting(this.config, this.root.descendants, this.relativePath === undefined);
+ if (nesting !== GitExplorerFilesLayout.List) {
+ children = [];
+ for (const folder of Objects.values(this.root.children)) {
+ if (folder.value === undefined) {
+ children.push(new FolderNode(this.repoPath, folder.name, folder.relativePath, folder, this.config));
+ continue;
+ }
+
+ folder.value.relativePath = this.root.relativePath;
+ children.push(folder.value);
+ }
+ }
+ else {
+ this.root.descendants.forEach(n => n.relativePath = this.root.relativePath);
+ children = this.root.descendants;
+ }
+
+ children.sort((a, b) => {
+ return ((a instanceof FolderNode) ? -1 : 1) - ((b instanceof FolderNode) ? -1 : 1) ||
+ (a.priority ? -1 : 1) - (b.priority ? -1 : 1) ||
+ a.label!.localeCompare(b.label!);
+ });
+
+ return children;
+ }
+
+ async getTreeItem(): Promise {
+ // TODO: Change this to expanded once https://github.com/Microsoft/vscode/issues/30918 is fixed
+ const item = new TreeItem(this.label, TreeItemCollapsibleState.Collapsed);
+ item.contextValue = this.resourceType;
+ return item;
+ }
+
+ get label(): string {
+ return this.folderName;
+ }
+
+ static getFileNesting(config: IGitExplorerConfig, children: T[], isRoot: boolean): GitExplorerFilesLayout {
+ const nesting = config.files.layout || GitExplorerFilesLayout.Auto;
+ if (nesting === GitExplorerFilesLayout.Auto) {
+ if (isRoot || config.files.compact) {
+ const nestingThreshold = config.files.threshold || 5;
+ if (children.length <= nestingThreshold) return GitExplorerFilesLayout.List;
+ }
+ return GitExplorerFilesLayout.Tree;
+ }
+ return nesting;
+ }
+}
\ No newline at end of file
diff --git a/src/views/statusFileCommitsNode.ts b/src/views/statusFileCommitsNode.ts
index 49c3f6c..557a356 100644
--- a/src/views/statusFileCommitsNode.ts
+++ b/src/views/statusFileCommitsNode.ts
@@ -3,7 +3,7 @@ import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } fr
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ExplorerNode, ResourceType } from './explorerNode';
-import { getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, IGitStatusFile, IGitStatusFileWithCommit, StatusFileFormatter } from '../gitService';
+import { getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, IGitStatusFile, IGitStatusFileWithCommit, IStatusFormatOptions, StatusFileFormatter } from '../gitService';
import * as path from 'path';
export class StatusFileCommitsNode extends ExplorerNode {
@@ -11,7 +11,7 @@ export class StatusFileCommitsNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status-file-commits';
constructor(
- repoPath: string,
+ public readonly repoPath: string,
public readonly status: IGitStatusFile,
public commits: GitLogCommit[],
protected readonly context: ExtensionContext,
@@ -47,10 +47,20 @@ export class StatusFileCommitsNode extends ExplorerNode {
return item;
}
+ private _folderName: string | undefined;
+ get folderName() {
+ if (this._folderName === undefined) {
+ this._folderName = path.dirname(this.uri.getRelativePath());
+ }
+ return this._folderName;
+ }
+
private _label: string | undefined;
get label() {
if (this._label === undefined) {
- this._label = StatusFileFormatter.fromTemplate(this.git.config.gitExplorer.statusFileFormat, { ...this.status, commit: this.commit } as IGitStatusFileWithCommit);
+ this._label = StatusFileFormatter.fromTemplate(this.git.config.gitExplorer.statusFileFormat,
+ { ...this.status, commit: this.commit } as IGitStatusFileWithCommit,
+ { relativePath: this.relativePath } as IStatusFormatOptions);
}
return this._label;
}
@@ -59,12 +69,25 @@ export class StatusFileCommitsNode extends ExplorerNode {
return this.commits[0];
}
+ get priority(): boolean {
+ return this.commit.isUncommitted;
+ }
+
+ private _relativePath: string | undefined;
+ get relativePath(): string | undefined {
+ return this._relativePath;
+ }
+ set relativePath(value: string | undefined) {
+ this._relativePath = value;
+ this._label = undefined;
+ }
+
getCommand(): Command | undefined {
return {
title: 'Compare File with Previous Revision',
command: Commands.DiffWithPrevious,
arguments: [
- GitUri.fromFileStatus(this.status, this.uri.repoPath!),
+ GitUri.fromFileStatus(this.status, this.repoPath),
{
commit: this.commit,
line: 0,
diff --git a/src/views/statusFilesNode.ts b/src/views/statusFilesNode.ts
index 8c71ec0..7a5482d 100644
--- a/src/views/statusFilesNode.ts
+++ b/src/views/statusFilesNode.ts
@@ -1,12 +1,16 @@
'use strict';
import { Arrays, Iterables, Objects } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
+import { GitExplorerFilesLayout } from '../configuration';
import { ExplorerNode, ResourceType, ShowAllNode } from './explorerNode';
+import { FolderNode, IFileExplorerNode } from './folderNode';
import { GitBranch, GitLog, GitLogCommit, GitService, GitStatus, GitUri, IGitStatusFileWithCommit } from '../gitService';
import { StatusFileCommitsNode } from './statusFileCommitsNode';
+import * as path from 'path';
export class StatusFilesNode extends ExplorerNode {
+ readonly repoPath: string;
readonly resourceType: ResourceType = 'gitlens:status-files';
maxCount: number | undefined = undefined;
@@ -19,14 +23,17 @@ export class StatusFilesNode extends ExplorerNode {
public readonly branch?: GitBranch
) {
super(new GitUri(Uri.file(status.repoPath), { repoPath: status.repoPath, fileName: status.repoPath }));
+ this.repoPath = status.repoPath;
}
async getChildren(): Promise {
let statuses: IGitStatusFileWithCommit[] = [];
+ const repoPath = this.repoPath;
+
let log: GitLog | undefined;
if (this.range !== undefined) {
- log = await this.git.getLogForRepo(this.status.repoPath, this.range, this.maxCount);
+ log = await this.git.getLogForRepo(repoPath, this.range, this.maxCount);
if (log !== undefined) {
statuses = Array.from(Iterables.flatMap(log.commits.values(), c => {
return c.fileStatuses.map(s => {
@@ -38,22 +45,33 @@ export class StatusFilesNode extends ExplorerNode {
if (this.status.files.length !== 0 && this.includeWorkingTree) {
statuses.splice(0, 0, ...this.status.files.map(s => {
- return { ...s, commit: new GitLogCommit('file', this.status.repoPath, GitService.uncommittedSha, s.fileName, 'You', new Date(), '', s.status, [s], s.originalFileName, 'HEAD', s.fileName) } as IGitStatusFileWithCommit;
+ return {
+ ...s,
+ commit: new GitLogCommit('file', repoPath, GitService.uncommittedSha, s.fileName, 'You', new Date(), '', s.status, [s], s.originalFileName, 'HEAD', s.fileName)
+ } as IGitStatusFileWithCommit;
}));
}
statuses.sort((a, b) => b.commit.date.getTime() - a.commit.date.getTime());
const groups = Arrays.groupBy(statuses, s => s.fileName);
- const children: (StatusFileCommitsNode | ShowAllNode)[] = [
- ...Iterables.map(Objects.values(groups),
- statuses => new StatusFileCommitsNode(this.uri.repoPath!, statuses[statuses.length - 1], statuses.map(s => s.commit), this.context, this.git, this.branch))
+ let children: IFileExplorerNode[] = [
+ ...Iterables.map(Objects.values(groups), statuses => new StatusFileCommitsNode(repoPath, statuses[statuses.length - 1], statuses.map(s => s.commit), this.context, this.git, this.branch))
];
- children.sort((a: StatusFileCommitsNode, b: StatusFileCommitsNode) => (a.commit.isUncommitted ? -1 : 1) - (b.commit.isUncommitted ? -1 : 1) || a.label!.localeCompare(b.label!));
+ if (this.git.config.gitExplorer.files.layout !== GitExplorerFilesLayout.List) {
+ const hierarchy = Arrays.makeHierarchical(children, n => n.uri.getRelativePath().split('/'),
+ (...paths: string[]) => GitService.normalizePath(path.join(...paths)), this.git.config.gitExplorer.files.compact);
+
+ const root = new FolderNode(repoPath, '', undefined, hierarchy, this.git.config.gitExplorer);
+ children = await root.getChildren() as IFileExplorerNode[];
+ }
+ else {
+ children.sort((a, b) => (a.priority ? -1 : 1) - (b.priority ? -1 : 1) || a.label!.localeCompare(b.label!));
+ }
if (log !== undefined && log.truncated) {
- children.push(new ShowAllNode('Show All Changes', this, this.context));
+ (children as (IFileExplorerNode | ShowAllNode)[]).push(new ShowAllNode('Show All Changes', this, this.context));
}
return children;
}
@@ -62,7 +80,7 @@ export class StatusFilesNode extends ExplorerNode {
let files = (this.status.files !== undefined && this.includeWorkingTree) ? this.status.files.length : 0;
if (this.status.upstream !== undefined) {
- const stats = await this.git.getChangedFilesCount(this.status.repoPath, `${this.status.upstream}...`);
+ const stats = await this.git.getChangedFilesCount(this.repoPath, `${this.status.upstream}...`);
if (stats !== undefined) {
files += stats.files;
}
@@ -82,5 +100,4 @@ export class StatusFilesNode extends ExplorerNode {
private get includeWorkingTree(): boolean {
return this.git.config.gitExplorer.includeWorkingTree;
}
-
}
\ No newline at end of file