Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 

365 рядки
9.6 KiB

import {
CancellationToken,
commands,
ConfigurationChangeEvent,
Disposable,
ProgressLocation,
TreeItem,
TreeItemCollapsibleState,
window,
} from 'vscode';
import {
BranchesViewConfig,
configuration,
ViewBranchesLayout,
ViewFilesLayout,
ViewShowBranchComparison,
} from '../configuration';
import { Commands } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitUri';
import {
GitBranchReference,
GitCommit,
GitReference,
GitRevisionReference,
RepositoryChange,
RepositoryChangeComparisonMode,
RepositoryChangeEvent,
} from '../git/models';
import { executeCommand } from '../system/command';
import { gate } from '../system/decorators/gate';
import {
BranchesNode,
BranchNode,
BranchOrTagFolderNode,
RepositoriesSubscribeableNode,
RepositoryFolderNode,
RepositoryNode,
ViewNode,
} from './nodes';
import { ViewBase } from './viewBase';
export class BranchesRepositoryNode extends RepositoryFolderNode<BranchesView, BranchesNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.child == null) {
this.child = new BranchesNode(this.uri, this.view, this, this.repo);
}
return this.child.getChildren();
}
protected changed(e: RepositoryChangeEvent) {
return e.changed(
RepositoryChange.Config,
RepositoryChange.Heads,
RepositoryChange.Index,
RepositoryChange.Remotes,
RepositoryChange.RemoteProviders,
RepositoryChange.Status,
RepositoryChange.Unknown,
RepositoryChangeComparisonMode.Any,
);
}
}
export class BranchesViewNode extends RepositoriesSubscribeableNode<BranchesView, BranchesRepositoryNode> {
async getChildren(): Promise<ViewNode[]> {
if (this.children == null) {
const repositories = this.view.container.git.openRepositories;
if (repositories.length === 0) {
this.view.message = 'No branches could be found.';
return [];
}
this.view.message = undefined;
const splat = repositories.length === 1;
this.children = repositories.map(
r => new BranchesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
if (this.children.length === 1) {
const [child] = this.children;
const branches = await child.repo.getBranches({ filter: b => !b.remote });
if (branches.values.length === 0) {
this.view.message = 'No branches could be found.';
this.view.title = 'Branches';
void child.ensureSubscription();
return [];
}
this.view.message = undefined;
this.view.title = `Branches (${branches.values.length})`;
return child.getChildren();
}
return this.children;
}
getTreeItem(): TreeItem {
const item = new TreeItem('Branches', TreeItemCollapsibleState.Expanded);
return item;
}
}
export class BranchesView extends ViewBase<BranchesViewNode, BranchesViewConfig> {
protected readonly configKey = 'branches';
constructor(container: Container) {
super('gitlens.views.branches', 'Branches', container);
}
override get canReveal(): boolean {
return this.config.reveal || !configuration.get('views.repositories.showBranches');
}
protected getRoot() {
return new BranchesViewNode(this);
}
protected registerCommands(): Disposable[] {
void this.container.viewCommands;
return [
commands.registerCommand(
this.getQualifiedCommand('copy'),
() => executeCommand(Commands.ViewsCopy, this.selection),
this,
),
commands.registerCommand(
this.getQualifiedCommand('refresh'),
() => {
this.container.git.resetCaches('branches');
return this.refresh(true);
},
this,
),
commands.registerCommand(
this.getQualifiedCommand('setLayoutToList'),
() => this.setLayout(ViewBranchesLayout.List),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setLayoutToTree'),
() => this.setLayout(ViewBranchesLayout.Tree),
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,
),
commands.registerCommand(
this.getQualifiedCommand('setShowAvatarsOn'),
() => this.setShowAvatars(true),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setShowAvatarsOff'),
() => this.setShowAvatars(false),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setShowBranchComparisonOn'),
() => this.setShowBranchComparison(true),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setShowBranchComparisonOff'),
() => this.setShowBranchComparison(false),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setShowBranchPullRequestOn'),
() => this.setShowBranchPullRequest(true),
this,
),
commands.registerCommand(
this.getQualifiedCommand('setShowBranchPullRequestOff'),
() => this.setShowBranchPullRequest(false),
this,
),
];
}
protected override filterConfigurationChanged(e: ConfigurationChangeEvent) {
const changed = super.filterConfigurationChanged(e);
if (
!changed &&
!configuration.changed(e, 'defaultDateFormat') &&
!configuration.changed(e, 'defaultDateShortFormat') &&
!configuration.changed(e, 'defaultDateSource') &&
!configuration.changed(e, 'defaultDateStyle') &&
!configuration.changed(e, 'defaultGravatarsStyle') &&
!configuration.changed(e, 'defaultTimeFormat') &&
!configuration.changed(e, 'sortBranchesBy')
) {
return false;
}
return true;
}
findBranch(branch: GitBranchReference, token?: CancellationToken) {
if (branch.remote) return undefined;
const repoNodeId = RepositoryNode.getId(branch.repoPath);
return this.findNode((n: any) => n.branch?.ref === branch.ref, {
allowPaging: true,
maxDepth: 4,
canTraverse: n => {
if (n instanceof BranchesViewNode) return true;
if (n instanceof BranchesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
return false;
},
token: token,
});
}
async findCommit(commit: GitCommit | { repoPath: string; ref: string }, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(commit.repoPath);
// Get all the branches the commit is on
const branches = await this.container.git.getCommitBranches(
commit.repoPath,
commit.ref,
GitCommit.is(commit) ? { commitDate: commit.committer.date } : undefined,
);
if (branches.length === 0) return undefined;
return this.findNode((n: any) => n.commit?.ref === commit.ref, {
allowPaging: true,
maxDepth: 5,
canTraverse: async n => {
if (n instanceof BranchesViewNode) return true;
if (n instanceof BranchesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
if (n instanceof BranchNode && branches.includes(n.branch.name)) {
await n.loadMore({ until: commit.ref });
return true;
}
return false;
},
token: token,
});
}
@gate(() => '')
revealBranch(
branch: GitBranchReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(branch, { icon: false, quoted: true })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findBranch(branch, token);
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
return node;
},
);
}
@gate(() => '')
async revealCommit(
commit: GitRevisionReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(commit, { icon: false, quoted: true })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findCommit(commit, token);
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
return node;
},
);
}
@gate(() => '')
async revealRepository(
repoPath: string,
options?: { select?: boolean; focus?: boolean; expand?: boolean | number },
) {
const node = await this.findNode(RepositoryFolderNode.getId(repoPath), {
maxDepth: 1,
canTraverse: n => n instanceof BranchesViewNode || n instanceof RepositoryFolderNode,
});
if (node !== undefined) {
await this.reveal(node, options);
}
return node;
}
private setLayout(layout: ViewBranchesLayout) {
return configuration.updateEffective(`views.${this.configKey}.branches.layout` as const, layout);
}
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective(`views.${this.configKey}.files.layout` as const, layout);
}
private setShowAvatars(enabled: boolean) {
return configuration.updateEffective(`views.${this.configKey}.avatars` as const, enabled);
}
private setShowBranchComparison(enabled: boolean) {
return configuration.updateEffective(
`views.${this.configKey}.showBranchComparison` as const,
enabled ? ViewShowBranchComparison.Branch : false,
);
}
private async setShowBranchPullRequest(enabled: boolean) {
await configuration.updateEffective(`views.${this.configKey}.pullRequests.showForBranches` as const, enabled);
await configuration.updateEffective(`views.${this.configKey}.pullRequests.enabled` as const, enabled);
}
}