Adds working tree status to custom view (insiders)

Hides working changed files behind insiders flag
Unhides Changed Files node from behind insiders flag
Adds changed file count to Changed Files node label
Adds icon to Changed Files node
Adds upstream branch to upstream status nodes
Sorts files in the Changed Files node
This commit is contained in:
Eric Amodio
2017-09-20 01:36:21 -04:00
parent 712544fab8
commit f7df845dfe
14 changed files with 81 additions and 27 deletions

View File

@@ -324,6 +324,7 @@ export interface IConfig {
commitFileFormat: string;
stashFormat: string;
stashFileFormat: string;
statusFileFormat: string;
// dateFormat: string | null;
};

View File

@@ -81,10 +81,12 @@ export type GlyphChars = '\u21a9' |
'\u21e8' |
'\u2191' |
'\u2197' |
'\u2217' |
'\u2713' |
'\u2014' |
'\u2022' |
'\u2026' |
'\u270E' |
'\u00a0' |
'\u200b';
export const GlyphChars = {
@@ -97,10 +99,12 @@ export const GlyphChars = {
ArrowRightHollow: '\u21e8' as GlyphChars,
ArrowUp: '\u2191' as GlyphChars,
ArrowUpRight: '\u2197' as GlyphChars,
Asterisk: '\u2217' as GlyphChars,
Check: '\u2713' as GlyphChars,
Dash: '\u2014' as GlyphChars,
Dot: '\u2022' as GlyphChars,
Ellipsis: '\u2026' as GlyphChars,
Pensil: '\u270E' as GlyphChars,
Space: '\u00a0' as GlyphChars,
ZeroWidthSpace: '\u200b' as GlyphChars
};

View File

@@ -1,7 +1,8 @@
'use strict';
import { Strings } from '../../system';
import { GlyphChars } from '../../constants';
import { Formatter, IFormatOptions } from './formatter';
import { GitStatusFile, IGitStatusFile } from '../models/status';
import { GitStatusFile, IGitStatusFile, IGitStatusFileWithCommit } from '../models/status';
import * as path from 'path';
export interface IStatusFormatOptions extends IFormatOptions {
@@ -29,6 +30,11 @@ export class StatusFileFormatter extends Formatter<IGitStatusFile, IStatusFormat
return this._padOrTruncate(directory, this._options.tokenOptions!.file);
}
get working() {
const commit = (this._item as IGitStatusFileWithCommit).commit;
return (commit !== undefined && commit.isUncommitted) ? `${GlyphChars.Pensil} ${GlyphChars.Space}` : '';
}
static fromTemplate(template: string, status: IGitStatusFile, dateFormat: string | null): string;
static fromTemplate(template: string, status: IGitStatusFile, options?: IStatusFormatOptions): string;
static fromTemplate(template: string, status: IGitStatusFile, dateFormatOrOptions?: string | null | IStatusFormatOptions): string;

View File

@@ -3,6 +3,7 @@ import { Strings } from '../../system';
import { Uri } from 'vscode';
import { GlyphChars } from '../../constants';
import { GitUri } from '../gitUri';
import { GitLogCommit } from './logCommit';
import * as path from 'path';
export interface GitStatus {
@@ -27,6 +28,10 @@ export interface IGitStatusFile {
originalFileName?: string;
}
export interface IGitStatusFileWithCommit extends IGitStatusFile {
commit: GitLogCommit;
}
export class GitStatusFile implements IGitStatusFile {
originalFileName?: string;

View File

@@ -116,7 +116,8 @@ export class GitExplorer implements TreeDataProvider<ExplorerNode> {
private onConfigurationChanged() {
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
if (!Objects.areEquivalent(cfg.gitExplorer, this._config && this._config.gitExplorer)) {
if (!Objects.areEquivalent(cfg.gitExplorer, this._config && this._config.gitExplorer) ||
!Objects.areEquivalent(cfg.insiders, this._config && this._config.insiders)) {
setTimeout(() => {
this._root = this.getRootNode(window.activeTextEditor);
this.refresh();

View File

@@ -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, StatusFileFormatter } from '../gitService';
import { getGitStatusIcon, GitBranch, GitLogCommit, GitService, GitUri, IGitStatusFile, IGitStatusFileWithCommit, StatusFileFormatter } from '../gitService';
import * as path from 'path';
export class StatusFileCommitsNode extends ExplorerNode {
@@ -26,7 +26,7 @@ export class StatusFileCommitsNode extends ExplorerNode {
}
async getTreeItem(): Promise<TreeItem> {
const item = new TreeItem(StatusFileFormatter.fromTemplate(this.git.config.gitExplorer.commitFileFormat, this.status), TreeItemCollapsibleState.Collapsed);
const item = new TreeItem(this.label, TreeItemCollapsibleState.Collapsed);
item.contextValue = this.resourceType;
const icon = getGitStatusIcon(this.status.status);
@@ -41,9 +41,20 @@ export class StatusFileCommitsNode extends ExplorerNode {
item.command = this.getCommand();
}
// Only cache the label for a single refresh
this._label = undefined;
return item;
}
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);
}
return this._label;
}
get commit() {
return this.commits[0];
}

View File

@@ -2,13 +2,9 @@
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 { GitBranch, GitLog, GitLogCommit, GitService, GitStatus, GitUri, IGitStatusFileWithCommit } from '../gitService';
import { StatusFileCommitsNode } from './statusFileCommitsNode';
interface IGitStatusFileWithCommit extends IGitStatusFile {
commit: GitLogCommit;
}
export class StatusFilesNode extends ExplorerNode {
readonly resourceType: ResourceType = 'gitlens:status-files';
@@ -42,7 +38,7 @@ export class StatusFilesNode extends ExplorerNode {
statuses = [];
}
if (this.status.files.length !== 0) {
if (this.status.files.length !== 0 && this.git.config.insiders) {
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;
}));
@@ -56,6 +52,8 @@ export class StatusFilesNode extends ExplorerNode {
statuses => new StatusFileCommitsNode(this.uri.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 (log !== undefined && log.truncated) {
children.push(new ShowAllNode('Show All Changes', this, this.context));
}
@@ -63,8 +61,17 @@ export class StatusFilesNode extends ExplorerNode {
}
async getTreeItem(): Promise<TreeItem> {
const item = new TreeItem(`Changed Files`, TreeItemCollapsibleState.Collapsed);
const stats = await this.git.getChangedFilesCount(this.status.repoPath, this.git.config.insiders ? this.status.upstream : this.range);
const files = (stats === undefined) ? 0 : stats.files;
const label = `${files} file${files > 1 ? 's' : ''} changed`; // ${this.status.upstream === undefined ? '' : ` (ahead of ${this.status.upstream})`}`;
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
item.contextValue = this.resourceType;
item.iconPath = {
dark: this.context.asAbsolutePath(`images/dark/icon-diff.svg`),
light: this.context.asAbsolutePath(`images/light/icon-diff.svg`)
};
return item;
}
}

View File

@@ -30,11 +30,11 @@ export class StatusNode extends ExplorerNode {
children.push(new StatusUpstreamNode(status, 'ahead', this.context, this.git));
}
if (status.files.length !== 0 || status.state.ahead && this.git.config.insiders) {
if (status.state.ahead || (status.files.length !== 0 && 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));
children.push(new StatusFilesNode(status, range, this.context, this.git));
}
return children;
@@ -45,14 +45,16 @@ export class StatusNode extends ExplorerNode {
if (status === undefined) return new TreeItem('No repo status');
let hasChildren = false;
const hasWorkingChanges = status.files.length !== 0 && this.git.config.insiders;
let label = '';
let iconSuffix = '';
if (status.upstream) {
if (!status.state.ahead && !status.state.behind) {
label = `${status.branch} is up-to-date with ${status.upstream}`;
label = `${status.branch}${hasWorkingChanges ? ' has uncommitted changes and' : ''} is up-to-date with ${status.upstream}`;
}
else {
label = `${status.branch} is not up-to-date with ${status.upstream}`;
label = `${status.branch}${hasWorkingChanges ? ' has uncommitted changes and' : ''} is not up-to-date with ${status.upstream}`;
hasChildren = true;
if (status.state.ahead && status.state.behind) {
iconSuffix = '-yellow';
@@ -66,14 +68,10 @@ export class StatusNode extends ExplorerNode {
}
}
else {
label = `${status.branch} is up-to-date`;
label = `${status.branch} ${hasWorkingChanges ? 'has uncommitted changes' : 'is clean'}`;
}
if (this.git.config.insiders) {
hasChildren = hasChildren || status.files.length !== 0;
}
const item = new TreeItem(label, hasChildren ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None);
const item = new TreeItem(label, (hasChildren || hasWorkingChanges) ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None);
item.contextValue = this.resourceType;
item.iconPath = {

View File

@@ -43,8 +43,8 @@ export class StatusUpstreamNode extends ExplorerNode {
async getTreeItem(): Promise<TreeItem> {
const label = this.direction === 'ahead'
? `${this.status.state.ahead} commit${this.status.state.ahead > 1 ? 's' : ''} ahead (local changes)` // of ${this.status.upstream}`
: `${this.status.state.behind} commit${this.status.state.behind > 1 ? 's' : ''} behind (remote changes)`; // ${this.status.upstream}`;
? `${this.status.state.ahead} commit${this.status.state.ahead > 1 ? 's' : ''} (ahead of ${this.status.upstream})`
: `${this.status.state.behind} commit${this.status.state.behind > 1 ? 's' : ''} (behind ${this.status.upstream})`;
const item = new TreeItem(label, TreeItemCollapsibleState.Collapsed);
item.contextValue = this.resourceType;