'use strict';
|
|
import {
|
|
CancellationToken,
|
|
commands,
|
|
ConfigurationChangeEvent,
|
|
ProgressLocation,
|
|
TreeItem,
|
|
TreeItemCollapsibleState,
|
|
window,
|
|
} from 'vscode';
|
|
import { configuration, StashesViewConfig, ViewFilesLayout } from '../configuration';
|
|
import { Container } from '../container';
|
|
import { GitReference, GitStashReference, Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
|
|
import { GitUri } from '../git/gitUri';
|
|
import {
|
|
ContextValues,
|
|
MessageNode,
|
|
RepositoryNode,
|
|
StashesNode,
|
|
StashNode,
|
|
SubscribeableViewNode,
|
|
unknownGitUri,
|
|
ViewNode,
|
|
} from './nodes';
|
|
import { debug, gate } from '../system';
|
|
import { ViewBase } from './viewBase';
|
|
|
|
export class StashesRepositoryNode extends SubscribeableViewNode<StashesView> {
|
|
protected splatted = true;
|
|
private child: StashesNode | undefined;
|
|
|
|
constructor(uri: GitUri, view: StashesView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
|
|
super(uri, view, parent);
|
|
|
|
this.splatted = splatted;
|
|
}
|
|
|
|
get id(): string {
|
|
return RepositoryNode.getId(this.repo.path);
|
|
}
|
|
|
|
async getChildren(): Promise<ViewNode[]> {
|
|
if (this.child == null) {
|
|
this.child = new StashesNode(this.uri, this.view, this, this.repo);
|
|
}
|
|
|
|
return this.child.getChildren();
|
|
}
|
|
|
|
getTreeItem(): TreeItem {
|
|
this.splatted = false;
|
|
|
|
const item = new TreeItem(
|
|
this.repo.formattedName ?? this.uri.repoPath ?? '',
|
|
TreeItemCollapsibleState.Expanded,
|
|
);
|
|
item.contextValue = ContextValues.RepositoryFolder;
|
|
|
|
return item;
|
|
}
|
|
|
|
async getSplattedChild() {
|
|
if (this.child == null) {
|
|
await this.getChildren();
|
|
}
|
|
|
|
return this.child;
|
|
}
|
|
|
|
@gate()
|
|
@debug()
|
|
async refresh(reset: boolean = false) {
|
|
await this.child?.triggerChange(reset);
|
|
|
|
await this.ensureSubscription();
|
|
}
|
|
|
|
@debug()
|
|
protected subscribe() {
|
|
return this.repo.onDidChange(this.onRepositoryChanged, this);
|
|
}
|
|
|
|
@debug({
|
|
args: {
|
|
0: (e: RepositoryChangeEvent) =>
|
|
`{ repository: ${e.repository?.name ?? ''}, changes: ${e.changes.join()} }`,
|
|
},
|
|
})
|
|
private onRepositoryChanged(e: RepositoryChangeEvent) {
|
|
if (e.changed(RepositoryChange.Closed)) {
|
|
this.dispose();
|
|
void this.parent?.triggerChange(true);
|
|
|
|
return;
|
|
}
|
|
|
|
if (e.changed(RepositoryChange.Config) || e.changed(RepositoryChange.Stash)) {
|
|
void this.triggerChange(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class StashesViewNode extends ViewNode<StashesView> {
|
|
protected splatted = true;
|
|
private children: StashesRepositoryNode[] | undefined;
|
|
|
|
constructor(view: StashesView) {
|
|
super(unknownGitUri, view);
|
|
}
|
|
|
|
async getChildren(): Promise<ViewNode[]> {
|
|
if (this.children == null) {
|
|
const repositories = await Container.git.getOrderedRepositories();
|
|
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No stashes could be found.')];
|
|
|
|
const splat = repositories.length === 1;
|
|
this.children = repositories.map(
|
|
r => new StashesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
|
|
);
|
|
}
|
|
|
|
if (this.children.length === 1) {
|
|
const [child] = this.children;
|
|
|
|
const stash = await child.repo.getStash();
|
|
this.view.title = `Stashes (${stash?.commits.size ?? 0})`;
|
|
|
|
return child.getChildren();
|
|
}
|
|
|
|
return this.children;
|
|
}
|
|
|
|
getTreeItem(): TreeItem {
|
|
const item = new TreeItem('Stashes', TreeItemCollapsibleState.Expanded);
|
|
return item;
|
|
}
|
|
|
|
async getSplattedChild() {
|
|
if (this.children == null) {
|
|
await this.getChildren();
|
|
}
|
|
|
|
return this.children?.length === 1 ? this.children[0] : undefined;
|
|
}
|
|
|
|
@gate()
|
|
@debug()
|
|
refresh(reset: boolean = false) {
|
|
if (reset && this.children != null) {
|
|
for (const child of this.children) {
|
|
child.dispose();
|
|
}
|
|
this.children = undefined;
|
|
}
|
|
}
|
|
}
|
|
|
|
export class StashesView extends ViewBase<StashesViewNode, StashesViewConfig> {
|
|
protected readonly configKey = 'stashes';
|
|
|
|
constructor() {
|
|
super('gitlens.views.stashes', 'Stashes');
|
|
}
|
|
|
|
getRoot() {
|
|
return new StashesViewNode(this);
|
|
}
|
|
|
|
protected registerCommands() {
|
|
void Container.viewCommands;
|
|
|
|
commands.registerCommand(
|
|
this.getQualifiedCommand('copy'),
|
|
() => commands.executeCommand('gitlens.views.copy', this.selection),
|
|
this,
|
|
);
|
|
commands.registerCommand(this.getQualifiedCommand('refresh'), () => this.refresh(true), this);
|
|
commands.registerCommand(
|
|
this.getQualifiedCommand('setFilesLayoutToAuto'),
|
|
() => this.setFilesLayout(ViewFilesLayout.Auto),
|
|
this,
|
|
);
|
|
commands.registerCommand(
|
|
this.getQualifiedCommand('setFilesLayoutToList'),
|
|
() => this.setFilesLayout(ViewFilesLayout.List),
|
|
this,
|
|
);
|
|
commands.registerCommand(
|
|
this.getQualifiedCommand('setFilesLayoutToTree'),
|
|
() => this.setFilesLayout(ViewFilesLayout.Tree),
|
|
this,
|
|
);
|
|
}
|
|
|
|
protected filterConfigurationChanged(e: ConfigurationChangeEvent) {
|
|
const changed = super.filterConfigurationChanged(e);
|
|
if (
|
|
!changed &&
|
|
!configuration.changed(e, 'defaultDateFormat') &&
|
|
!configuration.changed(e, 'defaultDateSource') &&
|
|
!configuration.changed(e, 'defaultDateStyle') &&
|
|
!configuration.changed(e, 'defaultGravatarsStyle')
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
findStash(stash: GitStashReference, token?: CancellationToken) {
|
|
const repoNodeId = RepositoryNode.getId(stash.repoPath);
|
|
|
|
return this.findNode(StashNode.getId(stash.repoPath, stash.ref), {
|
|
maxDepth: 2,
|
|
canTraverse: n => {
|
|
if (n instanceof StashesViewNode) return true;
|
|
|
|
if (n instanceof StashesRepositoryNode) {
|
|
return n.id.startsWith(repoNodeId);
|
|
}
|
|
|
|
return false;
|
|
},
|
|
token: token,
|
|
});
|
|
}
|
|
|
|
@gate(() => '')
|
|
async revealStash(
|
|
stash: GitStashReference,
|
|
options?: {
|
|
select?: boolean;
|
|
focus?: boolean;
|
|
expand?: boolean | number;
|
|
},
|
|
) {
|
|
return window.withProgress(
|
|
{
|
|
location: ProgressLocation.Notification,
|
|
title: `Revealing ${GitReference.toString(stash, { icon: false })} in the side bar...`,
|
|
cancellable: true,
|
|
},
|
|
async (progress, token) => {
|
|
const node = await this.findStash(stash, token);
|
|
if (node == null) return undefined;
|
|
|
|
await this.ensureRevealNode(node, options);
|
|
|
|
return node;
|
|
},
|
|
);
|
|
}
|
|
|
|
private setFilesLayout(layout: ViewFilesLayout) {
|
|
return configuration.updateEffective('views', this.configKey, 'files', 'layout', layout);
|
|
}
|
|
}
|