Переглянути джерело

Closes #139 - adds changed files node to repository status

Reworks commit-file nodes
main
Eric Amodio 7 роки тому
джерело
коміт
71d17bcc2f
23 змінених файлів з 365 додано та 79 видалено
  1. +2
    -0
      CHANGELOG.md
  2. +46
    -1
      package.json
  3. +1
    -1
      src/git/formatters/commit.ts
  4. +1
    -0
      src/gitService.ts
  5. +1
    -1
      src/system/array.ts
  6. +12
    -6
      src/views/branchHistoryNode.ts
  7. +6
    -2
      src/views/branchesNode.ts
  8. +41
    -6
      src/views/commitFileNode.ts
  9. +16
    -30
      src/views/commitNode.ts
  10. +6
    -3
      src/views/explorerNode.ts
  11. +3
    -1
      src/views/explorerNodes.ts
  12. +8
    -4
      src/views/fileHistoryNode.ts
  13. +6
    -2
      src/views/historyNode.ts
  14. +7
    -2
      src/views/remoteNode.ts
  15. +5
    -1
      src/views/remotesNode.ts
  16. +6
    -2
      src/views/repositoryNode.ts
  17. +16
    -3
      src/views/stashFileNode.ts
  18. +6
    -2
      src/views/stashNode.ts
  19. +6
    -2
      src/views/stashesNode.ts
  20. +68
    -0
      src/views/statusFileCommitsNode.ts
  21. +70
    -0
      src/views/statusFilesNode.ts
  22. +21
    -5
      src/views/statusNode.ts
  23. +11
    -5
      src/views/statusUpstreamNode.ts

+ 2
- 0
CHANGELOG.md Переглянути файл

@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]
### Added
- Adds new `Changed Files` node to the `Repository Status` node of the `GitLens` custom view's `Repository View` -- closes [#139](https://github.com/eamodio/vscode-gitlens/issues/139)
- Provides a file-based view of all the changed files in the working tree and/or files in commits that haven't yet been pushed upstream
- Adds `gitlens.gitExplorer.enabled` setting to specify whether or not to show the `GitLens` custom view - closes [#144](https://github.com/eamodio/vscode-gitlens/issues/144)
## [5.1.0] - 2017-09-15

+ 46
- 1
package.json Переглянути файл

@ -1743,8 +1743,53 @@
"group": "1_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChanges",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "1_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openChangesWithWorking",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "1_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openFile",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "2_gitlens@1"
},
{
"command": "gitlens.gitExplorer.openFileRevision",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "2_gitlens@2"
},
{
"command": "gitlens.openFileInRemote",
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "3_gitlens@1"
},
{
"command": "gitlens.showQuickFileHistory",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file && gitlens:gitExplorer:view == repository",
"group": "5_gitlens@1"
},
{
"command": "gitlens.showQuickCommitFileDetails",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file",
"group": "5_gitlens@2"
},
{
"command": "gitlens.gitExplorer.openFile",
"when": "view == gitlens.gitExplorer && viewItem == gitlens:status-file-commits",
"group": "1_gitlens@1"
},
{
"command": "gitlens.openFileInRemote",
"when": "gitlens:hasRemotes && view == gitlens.gitExplorer && viewItem == gitlens:status-file-commits",
"group": "1_gitlens@2"
},
{
"command": "gitlens.gitExplorer.refresh",
"when": "view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file",
"when": "view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file && viewItem != gitlens:status-file",
"group": "9_gitlens@1"
}
]

+ 1
- 1
src/git/formatters/commit.ts Переглянути файл

@ -39,7 +39,7 @@ export class CommitFormatter extends Formatter
}
get id() {
return this._item.shortSha;
return this._item.isUncommitted ? 'index' : this._item.shortSha;
}
get message() {

+ 1
- 0
src/gitService.ts Переглянути файл

@ -74,6 +74,7 @@ export const RepoChangedReasons = {
export class GitService extends Disposable {
static fakeSha = 'ffffffffffffffffffffffffffffffffffffffff';
static uncommittedSha = '0000000000000000000000000000000000000000';
private _onDidBlameFail = new EventEmitter<string>();
get onDidBlameFail(): Event<string> {

+ 1
- 1
src/system/array.ts Переглянути файл

@ -1,7 +1,7 @@
'use strict';
export namespace Arrays {
export function groupBy<T>(array: T[], accessor: (item: T) => any): T[] {
export function groupBy<T>(array: T[], accessor: (item: T) => string): { [key: string]: T[] } {
return array.reduce((previous, current) => {
const value = accessor(current);
previous[value] = previous[value] || [];

+ 12
- 6
src/views/branchHistoryNode.ts Переглянути файл

@ -3,7 +3,7 @@ import { Iterables } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { CommitNode } from './commitNode';
import { GlyphChars } from '../constants';
import { ExplorerNode, ResourceType, ShowAllCommitsNode } from './explorerNode';
import { ExplorerNode, ResourceType, ShowAllNode } from './explorerNode';
import { GitBranch, GitService, GitUri } from '../gitService';
export class BranchHistoryNode extends ExplorerNode {
@ -12,7 +12,12 @@ export class BranchHistoryNode extends ExplorerNode {
maxCount: number | undefined = undefined;
constructor(public readonly branch: GitBranch, uri: GitUri, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
public readonly branch: GitBranch,
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
@ -20,10 +25,11 @@ export class BranchHistoryNode extends ExplorerNode {
const log = await this.git.getLogForRepo(this.uri.repoPath!, this.branch.name, this.maxCount);
if (log === undefined) return [];
const children = Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git, this.branch));
if (!log.truncated) return [...children];
return [...children, new ShowAllCommitsNode(this, this.context)];
const children: (CommitNode | ShowAllNode)[] = [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.context, this.git, this.branch))];
if (log.truncated) {
children.push(new ShowAllNode('Show All Commits', this, this.context));
}
return children;
}
async getTreeItem(): Promise<TreeItem> {

+ 6
- 2
src/views/branchesNode.ts Переглянути файл

@ -9,7 +9,11 @@ export class BranchesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:branches';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
@ -18,7 +22,7 @@ export class BranchesNode extends ExplorerNode {
if (branches === undefined) return [];
branches.sort((a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || a.name.localeCompare(b.name));
return [...Iterables.filterMap(branches, b => b.remote ? undefined : new BranchHistoryNode(b, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
return [...Iterables.filterMap(branches, b => b.remote ? undefined : new BranchHistoryNode(b, this.uri, this.context, this.git))];
}
async getTreeItem(): Promise<TreeItem> {

+ 41
- 6
src/views/commitFileNode.ts Переглянути файл

@ -2,19 +2,36 @@
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { ExplorerNode, ResourceType } from './explorerNode';
import { getGitStatusIcon, GitBranch, GitCommit, GitService, GitUri, IGitStatusFile, StatusFileFormatter } from '../gitService';
import { CommitFormatter, getGitStatusIcon, GitBranch, GitCommit, GitService, GitUri, ICommitFormatOptions, IGitStatusFile, StatusFileFormatter } from '../gitService';
import * as path from 'path';
export enum CommitFileNodeDisplayAs {
CommitLabel = 1 << 0,
CommitIcon = 1 << 1,
FileLabel = 1 << 2,
StatusIcon = 1 << 3,
Commit = CommitLabel | CommitIcon,
File = FileLabel | StatusIcon
}
export class CommitFileNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:commit-file';
constructor(public readonly status: IGitStatusFile, public commit: GitCommit, protected readonly context: ExtensionContext, protected readonly git: GitService, public readonly branch?: GitBranch) {
constructor(
public readonly status: IGitStatusFile,
public commit: GitCommit,
protected readonly context: ExtensionContext,
protected readonly git: GitService,
private displayAs: CommitFileNodeDisplayAs = CommitFileNodeDisplayAs.Commit,
public readonly branch?: GitBranch
) {
super(new GitUri(Uri.file(path.resolve(commit.repoPath, status.fileName)), { repoPath: commit.repoPath, fileName: status.fileName, sha: commit.sha }));
}
getChildren(): Promise<ExplorerNode[]> {
return Promise.resolve([]);
async getChildren(): Promise<ExplorerNode[]> {
return [];
}
async getTreeItem(): Promise<TreeItem> {
@ -25,10 +42,20 @@ export class CommitFileNode extends ExplorerNode {
}
}
const item = new TreeItem(StatusFileFormatter.fromTemplate(this.git.config.gitExplorer.commitFileFormat, this.status), TreeItemCollapsibleState.None);
const label = (this.displayAs & CommitFileNodeDisplayAs.CommitLabel)
? CommitFormatter.fromTemplate(this.getCommitTemplate(), this.commit, {
truncateMessageAtNewLine: true,
dataFormat: this.git.config.defaultDateFormat
} as ICommitFormatOptions)
: StatusFileFormatter.fromTemplate(this.getCommitFileTemplate(), this.status);
const item = new TreeItem(label, TreeItemCollapsibleState.None);
item.contextValue = this.resourceType;
const icon = getGitStatusIcon(this.status.status);
const icon = (this.displayAs & CommitFileNodeDisplayAs.CommitIcon)
? 'icon-commit.svg'
: getGitStatusIcon(this.status.status);
item.iconPath = {
dark: this.context.asAbsolutePath(path.join('images', 'dark', icon)),
light: this.context.asAbsolutePath(path.join('images', 'light', icon))
@ -39,6 +66,14 @@ export class CommitFileNode extends ExplorerNode {
return item;
}
protected getCommitTemplate() {
return this.git.config.gitExplorer.commitFormat;
}
protected getCommitFileTemplate() {
return this.git.config.gitExplorer.commitFileFormat;
}
getCommand(): Command | undefined {
return {
title: 'Compare File with Previous Revision',

+ 16
- 30
src/views/commitNode.ts Переглянути файл

@ -2,58 +2,44 @@
import { Iterables } from '../system';
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { CommitFileNode } from './commitFileNode';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { CommitFormatter, getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, ICommitFormatOptions } from '../gitService';
import * as path from 'path';
import { CommitFormatter, GitBranch, GitLogCommit, GitService, GitUri, ICommitFormatOptions } from '../gitService';
export class CommitNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:commit';
constructor(public readonly commit: GitLogCommit, private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService, public readonly branch?: GitBranch) {
constructor(
public readonly commit: GitLogCommit,
protected readonly context: ExtensionContext,
protected readonly git: GitService,
public readonly branch?: GitBranch
) {
super(new GitUri(commit.uri, commit));
}
async getChildren(): Promise<ExplorerNode[]> {
if (this.commit.type === 'file') Promise.resolve([]);
const log = await this.git.getLogForRepo(this.commit.repoPath, this.commit.sha, 1);
if (log === undefined) return [];
const commit = Iterables.first(log.commits.values());
if (commit === undefined) return [];
return [...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git, this.branch))];
return [...Iterables.map(commit.fileStatuses, s => new CommitFileNode(s, commit, this.context, this.git, CommitFileNodeDisplayAs.File, this.branch))];
}
getTreeItem(): TreeItem {
const item = new TreeItem(CommitFormatter.fromTemplate(this.template, this.commit, {
const item = new TreeItem(CommitFormatter.fromTemplate(this.git.config.gitExplorer.commitFormat, this.commit, {
truncateMessageAtNewLine: true,
dataFormat: this.git.config.defaultDateFormat
} as ICommitFormatOptions));
if (this.commit.type === 'file') {
item.collapsibleState = TreeItemCollapsibleState.None;
item.command = this.getCommand();
const resourceType: ResourceType = 'gitlens:commit-file';
item.contextValue = resourceType;
} as ICommitFormatOptions), TreeItemCollapsibleState.Collapsed);
const icon = getGitStatusIcon(this.commit.status!);
item.iconPath = {
dark: this.context.asAbsolutePath(path.join('images', 'dark', icon)),
light: this.context.asAbsolutePath(path.join('images', 'light', icon))
};
}
else {
item.collapsibleState = TreeItemCollapsibleState.Collapsed;
item.contextValue = this.resourceType;
item.iconPath = {
dark: this.context.asAbsolutePath('images/dark/icon-commit.svg'),
light: this.context.asAbsolutePath('images/light/icon-commit.svg')
};
}
item.contextValue = this.resourceType;
item.iconPath = {
dark: this.context.asAbsolutePath('images/dark/icon-commit.svg'),
light: this.context.asAbsolutePath('images/light/icon-commit.svg')
};
return item;
}

+ 6
- 3
src/views/explorerNode.ts Переглянути файл

@ -20,6 +20,9 @@ export declare type ResourceType =
'gitlens:stash-file' |
'gitlens:stashes' |
'gitlens:status' |
'gitlens:status-file' |
'gitlens:status-files' |
'gitlens:status-file-commits' |
'gitlens:status-upstream';
export abstract class ExplorerNode {
@ -88,11 +91,11 @@ export class PagerNode extends ExplorerNode {
}
}
export class ShowAllCommitsNode extends PagerNode {
export class ShowAllNode extends PagerNode {
args: RefreshNodeCommandArgs = { maxCount: 0 };
constructor(node: ExplorerNode, context: ExtensionContext) {
super(`Show All Commits ${GlyphChars.Space}${GlyphChars.Dash}${GlyphChars.Space} this may take a while`, node, context);
constructor(message: string, node: ExplorerNode, context: ExtensionContext) {
super(`${message} ${GlyphChars.Space}${GlyphChars.Dash}${GlyphChars.Space} this may take a while`, node, context);
}
}

+ 3
- 1
src/views/explorerNodes.ts Переглянути файл

@ -10,8 +10,10 @@ export * from './historyNode';
export * from './remoteNode';
export * from './remotesNode';
export * from './repositoryNode';
export * from './stashesNode';
export * from './stashFileNode';
export * from './stashNode';
export * from './stashesNode';
export * from './statusFileCommitsNode';
export * from './statusFilesNode';
export * from './statusNode';
export * from './statusUpstreamNode';

+ 8
- 4
src/views/fileHistoryNode.ts Переглянути файл

@ -1,7 +1,7 @@
'use strict';
import { Iterables } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { CommitNode } from './commitNode';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ExplorerNode, MessageNode, ResourceType } from './explorerNode';
import { GitService, GitUri } from '../gitService';
@ -9,15 +9,19 @@ export class FileHistoryNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:file-history';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
}
async getChildren(): Promise<ExplorerNode[]> {
const log = await this.git.getLogForFile(this.uri.repoPath, this.uri.fsPath, this.uri.sha);
if (log === undefined) return [new MessageNode('No file history')];
return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
return [...Iterables.map(log.commits.values(), c => new CommitFileNode(c.fileStatuses[0], c, this.context, this.git, CommitFileNodeDisplayAs.CommitLabel | CommitFileNodeDisplayAs.StatusIcon))];
}
getTreeItem(): TreeItem {

+ 6
- 2
src/views/historyNode.ts Переглянути файл

@ -8,9 +8,13 @@ export class HistoryNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:history';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
}
async getChildren(): Promise<ExplorerNode[]> {
return [new FileHistoryNode(this.uri, this.context, this.git)];

+ 7
- 2
src/views/remoteNode.ts Переглянути файл

@ -10,7 +10,12 @@ export class RemoteNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:remote';
constructor(public readonly remote: GitRemote, uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
public readonly remote: GitRemote,
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
@ -19,7 +24,7 @@ export class RemoteNode extends ExplorerNode {
if (branches === undefined) return [];
branches.sort((a, b) => a.name.localeCompare(b.name));
return [...Iterables.filterMap(branches, b => !b.remote || !b.name.startsWith(this.remote.name) ? undefined : new BranchHistoryNode(b, this.uri, this.git.config.gitExplorer.commitFormat, this.context, this.git))];
return [...Iterables.filterMap(branches, b => !b.remote || !b.name.startsWith(this.remote.name) ? undefined : new BranchHistoryNode(b, this.uri, this.context, this.git))];
}
getTreeItem(): TreeItem {

+ 5
- 1
src/views/remotesNode.ts Переглянути файл

@ -9,7 +9,11 @@ export class RemotesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:remotes';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}

+ 6
- 2
src/views/repositoryNode.ts Переглянути файл

@ -12,9 +12,13 @@ export class RepositoryNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:repository';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
}
async getChildren(): Promise<ExplorerNode[]> {
return [

+ 16
- 3
src/views/stashFileNode.ts Переглянути файл

@ -2,13 +2,26 @@
import { ExtensionContext } from 'vscode';
import { ResourceType } from './explorerNode';
import { GitService, GitStashCommit, IGitStatusFile } from '../gitService';
import { CommitFileNode } from './commitFileNode';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
export class StashFileNode extends CommitFileNode {
readonly resourceType: ResourceType = 'gitlens:stash-file';
constructor(readonly status: IGitStatusFile, readonly commit: GitStashCommit, readonly context: ExtensionContext, readonly git: GitService) {
super(status, commit, context, git);
constructor(
readonly status: IGitStatusFile,
readonly commit: GitStashCommit,
readonly context: ExtensionContext,
readonly git: GitService
) {
super(status, commit, context, git, CommitFileNodeDisplayAs.File);
}
protected getCommitTemplate() {
return this.git.config.gitExplorer.stashFormat;
}
protected getCommitFileTemplate() {
return this.git.config.gitExplorer.stashFileFormat;
}
}

+ 6
- 2
src/views/stashNode.ts Переглянути файл

@ -9,7 +9,11 @@ export class StashNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:stash';
constructor(public readonly commit: GitStashCommit, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
public readonly commit: GitStashCommit,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(new GitUri(commit.uri, commit));
}
@ -27,7 +31,7 @@ export class StashNode extends ExplorerNode {
}
}
return Promise.resolve(statuses.map(s => new StashFileNode(s, this.commit, this.context, this.git)));
return statuses.map(s => new StashFileNode(s, this.commit, this.context, this.git));
}
getTreeItem(): TreeItem {

+ 6
- 2
src/views/stashesNode.ts Переглянути файл

@ -9,9 +9,13 @@ export class StashesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:stashes';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
}
async getChildren(): Promise<ExplorerNode[]> {
const stash = await this.git.getStashList(this.uri.repoPath!);

+ 68
- 0
src/views/statusFileCommitsNode.ts Переглянути файл

@ -0,0 +1,68 @@
'use strict';
import { Command, ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../commands';
import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, IGitStatusFile, StatusFileFormatter } from '../gitService';
import * as path from 'path';
export class StatusFileCommitsNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status-file-commits';
constructor(
repoPath: string,
public readonly status: IGitStatusFile,
public commits: GitLogCommit[],
protected readonly context: ExtensionContext,
protected readonly git: GitService,
public readonly branch?: GitBranch
) {
super(new GitUri(Uri.file(path.resolve(repoPath, status.fileName)), { repoPath: repoPath, fileName: status.fileName, sha: 'HEAD' }));
}
async getChildren(): Promise<ExplorerNode[]> {
return this.commits.map(c => new CommitFileNode(this.status, c, this.context, this.git, CommitFileNodeDisplayAs.Commit, this.branch));
}
async getTreeItem(): Promise<TreeItem> {
const item = new TreeItem(StatusFileFormatter.fromTemplate(this.git.config.gitExplorer.commitFileFormat, this.status), TreeItemCollapsibleState.Collapsed);
item.contextValue = this.resourceType;
const icon = getGitStatusIcon(this.status.status);
item.iconPath = {
dark: this.context.asAbsolutePath(path.join('images', 'dark', icon)),
light: this.context.asAbsolutePath(path.join('images', 'light', icon))
};
if (this.commits.length === 1 && this.commits[0].isUncommitted) {
item.collapsibleState = TreeItemCollapsibleState.None;
item.contextValue = 'gitlens:status-file' as ResourceType;
item.command = this.getCommand();
}
return item;
}
get commit() {
return this.commits[0];
}
getCommand(): Command | undefined {
return {
title: 'Compare File with Previous Revision',
command: Commands.DiffWithPrevious,
arguments: [
GitUri.fromFileStatus(this.status, this.uri.repoPath!),
{
commit: this.commit,
line: 0,
showOptions: {
preserveFocus: true,
preview: true
}
} as DiffWithPreviousCommandArgs
]
};
}
}

+ 70
- 0
src/views/statusFilesNode.ts Переглянути файл

@ -0,0 +1,70 @@
'use strict';
import { Arrays, Iterables, Objects } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { ExplorerNode, ResourceType, ShowAllNode } from './explorerNode';
import { GitBranch, GitLog, GitLogCommit, GitService, GitStatus, GitUri, IGitStatusFile } from '../gitService';
import { StatusFileCommitsNode } from './statusFileCommitsNode';
interface IGitStatusFileWithCommit extends IGitStatusFile {
commit: GitLogCommit;
}
export class StatusFilesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status-files';
maxCount: number | undefined = undefined;
constructor(
public readonly status: GitStatus,
public readonly range: string | undefined,
protected readonly context: ExtensionContext,
protected readonly git: GitService,
public readonly branch?: GitBranch
) {
super(new GitUri(Uri.file(status.repoPath), { repoPath: status.repoPath, fileName: status.repoPath }));
}
async getChildren(): Promise<ExplorerNode[]> {
let statuses: IGitStatusFileWithCommit[];
let log: GitLog | undefined;
if (this.range !== undefined) {
log = await this.git.getLogForRepo(this.status.repoPath, this.range, this.maxCount);
if (log === undefined) return [];
statuses = Array.from(Iterables.flatMap(log.commits.values(), c => {
return c.fileStatuses.map(s => {
return { ...s, commit: c } as IGitStatusFileWithCommit;
});
}));
}
else {
statuses = [];
}
if (this.status.files.length !== 0) {
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;
}));
}
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<IGitStatusFileWithCommit[]>(groups),
statuses => new StatusFileCommitsNode(this.uri.repoPath!, statuses[statuses.length - 1], statuses.map(s => s.commit), this.context, this.git, this.branch))
];
if (log !== undefined && log.truncated) {
children.push(new ShowAllNode('Show All Changes', this, this.context));
}
return children;
}
async getTreeItem(): Promise<TreeItem> {
const item = new TreeItem(`Changed Files`, TreeItemCollapsibleState.Collapsed);
item.contextValue = this.resourceType;
return item;
}
}

+ 21
- 5
src/views/statusNode.ts Переглянути файл

@ -1,28 +1,40 @@
import { ExtensionContext, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { GitService, GitUri } from '../gitService';
import { StatusFilesNode } from './statusFilesNode';
import { StatusUpstreamNode } from './statusUpstreamNode';
export class StatusNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status';
constructor(uri: GitUri, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
uri: GitUri,
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(uri);
}
}
async getChildren(): Promise<ExplorerNode[]> {
const status = await this.git.getStatusForRepo(this.uri.repoPath!);
if (status === undefined) return [];
const children = [];
const children: ExplorerNode[] = [];
if (status.state.behind) {
children.push(new StatusUpstreamNode(status, 'behind', this.git.config.gitExplorer.commitFormat, this.context, this.git));
children.push(new StatusUpstreamNode(status, 'behind', this.context, this.git));
}
if (status.state.ahead) {
children.push(new StatusUpstreamNode(status, 'ahead', this.git.config.gitExplorer.commitFormat, this.context, this.git));
children.push(new StatusUpstreamNode(status, 'ahead', this.context, this.git));
}
if (status.files.length !== 0 || status.state.ahead && this.git.config.insiders) {
const range = status.state.ahead
? `${status.upstream}..${status.branch}`
: undefined;
children.splice(0, 0, new StatusFilesNode(status, range, this.context, this.git));
}
return children;
@ -57,6 +69,10 @@ export class StatusNode extends ExplorerNode {
label = `${status.branch} is up-to-date`;
}
if (this.git.config.insiders) {
hasChildren = hasChildren || status.files.length !== 0;
}
const item = new TreeItem(label, hasChildren ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None);
item.contextValue = this.resourceType;

+ 11
- 5
src/views/statusUpstreamNode.ts Переглянути файл

@ -1,15 +1,20 @@
'use strict';
import { Iterables } from '../system';
import { ExtensionContext, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { CommitNode } from './commitNode';
import { ExplorerNode, ResourceType } from './explorerNode';
import { GitService, GitStatus, GitUri } from '../gitService';
import { CommitNode } from './commitNode';
export class StatusUpstreamNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status-upstream';
constructor(public readonly status: GitStatus, public readonly direction: 'ahead' | 'behind', private readonly template: string, protected readonly context: ExtensionContext, protected readonly git: GitService) {
constructor(
public readonly status: GitStatus,
public readonly direction: 'ahead' | 'behind',
protected readonly context: ExtensionContext,
protected readonly git: GitService
) {
super(new GitUri(Uri.file(status.repoPath), { repoPath: status.repoPath, fileName: status.repoPath }));
}
@ -17,10 +22,11 @@ export class StatusUpstreamNode extends ExplorerNode {
const range = this.direction === 'ahead'
? `${this.status.upstream}..${this.status.branch}`
: `${this.status.branch}..${this.status.upstream}`;
let log = await this.git.getLogForRepo(this.uri.repoPath!, range, 0);
if (log === undefined) return [];
if (this.direction !== 'ahead') return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.template, this.context, this.git))];
if (this.direction !== 'ahead') return [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.context, this.git))];
// Since the last commit when we are looking 'ahead' can have no previous (because of the range given) -- look it up
const commits = Array.from(log.commits.values());
@ -32,8 +38,8 @@ export class StatusUpstreamNode extends ExplorerNode {
}
}
return [...Iterables.map(commits, c => new CommitNode(c, this.template, this.context, this.git))];
}
return [...Iterables.map(commits, c => new CommitNode(c, this.context, this.git))];
}
async getTreeItem(): Promise<TreeItem> {
const label = this.direction === 'ahead'

Завантаження…
Відмінити
Зберегти