Skip to content

Commit

Permalink
Adds experimental compare branch node to repos
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed May 16, 2019
1 parent 2072f5a commit be6325f
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ export const ImageMimetypes: { [key: string]: string } = {
'.bmp': 'image/bmp'
};

export interface BranchComparisons {
[id: string]: string;
}

export interface NamedRef {
label?: string;
ref: string;
Expand All @@ -158,6 +162,7 @@ export interface StarredRepositories {
}

export enum WorkspaceState {
BranchComparisons = 'gitlens:branch:comparisons',
DefaultRemote = 'gitlens:remote:default',
PinnedComparisons = 'gitlens:pinned:comparisons',
StarredBranches = 'gitlens:starred:branches',
Expand Down
1 change: 1 addition & 0 deletions src/views/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './nodes/branchNode';
export * from './nodes/branchTrackingStatusNode';
export * from './nodes/commitFileNode';
export * from './nodes/commitNode';
export * from './nodes/compareBranchNode';
export * from './nodes/compareNode';
export * from './nodes/compareResultsNode';
export * from './nodes/contributorNode';
Expand Down
131 changes: 131 additions & 0 deletions src/views/nodes/compareBranchNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { BranchComparisons, GlyphChars, WorkspaceState } from '../../constants';
import { ResourceType, ViewNode } from './viewNode';
import { RepositoriesView } from '../repositoriesView';
import { GitBranch, GitService, GitUri } from '../../git/gitService';
import { CommandQuickPickItem, ReferencesQuickPick } from '../../quickpicks';
import { CommitsQueryResults, ResultsCommitsNode } from './resultsCommitsNode';
import { Container } from '../../container';
import { Strings } from '../../system';
import { ResultsFilesNode } from './resultsFilesNode';

export class CompareBranchNode extends ViewNode<RepositoriesView> {
private _children: ViewNode[] | undefined;
private _compareWith: string | undefined;

constructor(uri: GitUri, view: RepositoriesView, parent: ViewNode, public readonly branch: GitBranch) {
super(uri, view, parent);

const comparisons = Container.context.workspaceState.get<BranchComparisons>(WorkspaceState.BranchComparisons);
this._compareWith = comparisons && comparisons[branch.id];
}

get id(): string {
return `${this._instanceId}:gitlens:repository(${this.branch.repoPath}):branch(${
this.branch.name
}):compareWith`;
}

getChildren(): ViewNode[] {
if (this._compareWith === undefined) return [];

if (this._children === undefined) {
this._children = [
new ResultsCommitsNode(
this.view,
this,
this.uri.repoPath!,
'commits',
this.getCommitsQuery.bind(this),
{
expand: false,
includeDescription: false,
querying: true
}
),
new ResultsFilesNode(this.view, this, this.uri.repoPath!, this.branch.ref, this._compareWith)
];
}
return this._children;
}

getTreeItem(): TreeItem {
let state: TreeItemCollapsibleState;
let label;
if (this._compareWith === undefined) {
label = `Compare ${this.branch.name} with <branch, tag, or ref>`;
state = TreeItemCollapsibleState.None;
}
else {
label = `Comparing ${this.branch.name} to ${GitService.shortenSha(this._compareWith, {
working: 'Working Tree'
})}`;
state = TreeItemCollapsibleState.Collapsed;
}

const item = new TreeItem(label, state);
item.command = {
title: `Compare ${this.branch.name} with${GlyphChars.Ellipsis}`,
command: 'gitlens.views.executeNodeCallback',
arguments: [() => this.compareWith()]
};
item.contextValue = ResourceType.CompareBranch;
item.iconPath = {
dark: Container.context.asAbsolutePath('images/dark/icon-compare-refs.svg'),
light: Container.context.asAbsolutePath('images/light/icon-compare-refs.svg')
};
item.id = this.id;
item.tooltip = `Click to compare ${this.branch.name} with${GlyphChars.Ellipsis}`;

return item;
}

async compareWith() {
const pick = await new ReferencesQuickPick(this.branch.repoPath).show(
`Compare ${this.branch.name} with${GlyphChars.Ellipsis}`,
{ allowEnteringRefs: true }
);
if (pick === undefined || pick instanceof CommandQuickPickItem) return;

this._compareWith = pick.ref;
this.updateCompareWith(this._compareWith);

this._children = undefined;
this.view.triggerNodeChange(this);
}

private async getCommitsQuery(maxCount: number | undefined): Promise<CommitsQueryResults> {
const log = await Container.git.getLog(this.uri.repoPath!, {
maxCount: maxCount,
ref: `${this.branch.ref}...${this._compareWith || 'HEAD'}`
});

const count = log !== undefined ? log.count : 0;
const truncated = log !== undefined ? log.truncated : false;

const label = Strings.pluralize('commit', count, { number: truncated ? `${count}+` : undefined, zero: 'No' });

return {
label: label,
log: log
};
}

private async updateCompareWith(compareWith: string | undefined) {
let comparisons = Container.context.workspaceState.get<BranchComparisons>(WorkspaceState.BranchComparisons);
if (comparisons === undefined) {
comparisons = Object.create(null);
}

if (compareWith) {
comparisons![this.branch.id] = compareWith;
}
else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [this.branch.id]: _, ...rest } = comparisons!;
comparisons = rest;
}
await Container.context.workspaceState.update(WorkspaceState.BranchComparisons, comparisons);
}
}
7 changes: 5 additions & 2 deletions src/views/nodes/compareResultsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ export class CompareResultsNode extends SubscribeableViewNode<CompareView> {
this.uri.repoPath!,
'commits',
this.getCommitsQuery.bind(this),
true,
false
{
expand: false,
includeDescription: true,
querying: true
}
),
new ResultsFilesNode(this.view, this, this.uri.repoPath!, this._ref1.ref, this._ref2.ref)
];
Expand Down
5 changes: 5 additions & 0 deletions src/views/nodes/repositoryNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../../git/gitService';
import { Dates, debug, gate, log, Strings } from '../../system';
import { RepositoriesView } from '../repositoriesView';
import { CompareBranchNode } from './compareBranchNode';
import { BranchesNode } from './branchesNode';
import { BranchNode } from './branchNode';
import { BranchTrackingStatusNode } from './branchTrackingStatusNode';
Expand Down Expand Up @@ -74,6 +75,10 @@ export class RepositoryNode extends SubscribeableViewNode<RepositoriesView> {
children.push(new StatusFilesNode(this.view, this, status, range));
}

if (Container.config.insiders) {
children.push(new CompareBranchNode(this.uri, this.view, this, branch));
}

if (!this.view.config.repositories.compact) {
children.push(new MessageNode(this.view, this, '', GlyphChars.Dash.repeat(2), ''));
}
Expand Down
13 changes: 7 additions & 6 deletions src/views/nodes/resultsCommitsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ export class ResultsCommitsNode extends ViewNode<ViewWithFiles> implements Pagea
public readonly repoPath: string,
private _label: string,
private readonly _commitsQuery: (maxCount: number | undefined) => Promise<CommitsQueryResults>,
private _querying = true,
private readonly _expand = true
private readonly _options: { expand?: boolean; includeDescription?: boolean; querying?: boolean } = {}
) {
super(GitUri.fromRepoPath(repoPath), view, parent);

this._options = { expand: true, includeDescription: true, querying: true, ..._options };
}

get id(): string {
Expand Down Expand Up @@ -67,13 +68,13 @@ export class ResultsCommitsNode extends ViewNode<ViewWithFiles> implements Pagea
let state;
let label;
let log;
if (this._querying) {
if (this._options.querying) {
// Need to use Collapsed before we have results or the item won't show up in the view until the children are awaited
state = TreeItemCollapsibleState.Collapsed;
label = this._label;

this.getCommitsQueryResults().then(({ log }) => {
this._querying = false;
this._options.querying = false;
if (log != null) {
this.maxCount = log.maxCount;
}
Expand All @@ -87,14 +88,14 @@ export class ResultsCommitsNode extends ViewNode<ViewWithFiles> implements Pagea
this.maxCount = log.maxCount;
}

state = this._expand ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed;
state = this._options.expand ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed;
if (log == null || log.count === 0) {
state = TreeItemCollapsibleState.None;
}
}

let description;
if ((await Container.git.getRepositoryCount()) > 1) {
if (this._options.includeDescription && (await Container.git.getRepositoryCount()) > 1) {
const repo = await Container.git.getRepository(this.repoPath);
description = (repo && repo.formattedName) || this.repoPath;
}
Expand Down
6 changes: 5 additions & 1 deletion src/views/nodes/searchResultsCommitsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ export class SearchResultsCommitsNode extends ResultsCommitsNode {
commitsQuery: (maxCount: number | undefined) => Promise<CommitsQueryResults>,
_querying = true
) {
super(view, parent, repoPath, label, commitsQuery, _querying, true);
super(view, parent, repoPath, label, commitsQuery, {
expand: true,
includeDescription: true,
querying: _querying
});
}

get type(): ResourceType {
Expand Down
1 change: 1 addition & 0 deletions src/views/nodes/viewNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum ResourceType {
CommitFile = 'gitlens:file:commit',
Commits = 'gitlens:commits',
Compare = 'gitlens:compare',
CompareBranch = 'gitlens:compare:branch',
ComparePicker = 'gitlens:compare:picker',
ComparePickerWithRef = 'gitlens:compare:picker:ref',
CompareResults = 'gitlens:compare:results',
Expand Down
1 change: 1 addition & 0 deletions src/views/viewCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class ViewCommands implements Disposable {
(node: ViewNode) => viewSupportsNodeDismissal(node.view) && node.view.dismissNode(node),
this
);
commands.registerCommand('gitlens.views.executeNodeCallback', (fn: <R>() => Promise<R>) => fn(), this);
commands.registerCommand('gitlens.views.showAllChildren', (node: PagerNode) => node.showAll(), this);

commands.registerCommand('gitlens.views.fetch', this.fetch, this);
Expand Down

0 comments on commit be6325f

Please sign in to comment.