286 lines
9.2 KiB

'use strict';
import {
CancellationTokenSource,
commands,
QuickPickItem,
QuickPickOptions,
TextDocumentShowOptions,
TextEditor,
Uri,
window
} from 'vscode';
import { Commands, openEditor } from '../commands';
import { configuration } from '../configuration';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitLog, GitLogCommit, GitStashCommit } from '../gitService';
import { KeyMapping, Keys } from '../keyboard';
import { Strings } from '../system';
import { BranchesAndTagsQuickPick, BranchOrTagQuickPickItem } from './branchesAndTagsQuickPick';
export function getQuickPickIgnoreFocusOut() {
return !configuration.get<boolean>(configuration.name('advanced')('quickPick')('closeOnFocusOut').value);
}
export function showQuickPickProgress(message: string, mapping?: KeyMapping): CancellationTokenSource {
const cancellation = new CancellationTokenSource();
void _showQuickPickProgress(message, cancellation, mapping);
return cancellation;
}
async function _showQuickPickProgress(message: string, cancellation: CancellationTokenSource, mapping?: KeyMapping) {
const scope = mapping && (await Container.keyboard.beginScope(mapping));
try {
await window.showQuickPick(
_getInfiniteCancellablePromise(cancellation),
{
placeHolder: message,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions,
cancellation.token
);
}
catch (ex) {
// Not sure why this throws
}
finally {
cancellation.cancel();
scope && scope.dispose();
}
}
function _getInfiniteCancellablePromise(cancellation: CancellationTokenSource) {
return new Promise<QuickPickItem[]>((resolve, reject) => {
const disposable = cancellation.token.onCancellationRequested(() => {
disposable.dispose();
resolve([]);
});
});
}
export interface QuickPickItem extends QuickPickItem {
onDidSelect?(): void;
onDidPressKey?(key: Keys): Promise<{} | undefined>;
}
export class CommandQuickPickItem implements QuickPickItem {
label!: string;
description!: string;
detail?: string | undefined;
protected command: Commands | undefined;
protected args: any[] | undefined;
constructor(item: QuickPickItem, args?: [Commands, any[]]);
constructor(item: QuickPickItem, command?: Commands, args?: any[]);
constructor(item: QuickPickItem, commandOrArgs?: Commands | [Commands, any[]], args?: any[]) {
if (commandOrArgs === undefined) {
this.command = undefined;
this.args = args;
}
else if (typeof commandOrArgs === 'string') {
this.command = commandOrArgs;
this.args = args;
}
else {
this.command = commandOrArgs[0];
this.args = commandOrArgs.slice(1);
}
Object.assign(this, item);
}
execute(): Promise<{} | undefined> {
if (this.command === undefined) return Promise.resolve(undefined);
return commands.executeCommand(this.command, ...(this.args || [])) as Promise<{} | undefined>;
}
onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute();
}
}
export class CommitQuickPickItem implements QuickPickItem {
label: string;
description: string;
detail: string;
constructor(
public readonly commit: GitLogCommit
) {
const message = commit.getShortMessage();
if (commit.isStash) {
this.label = message;
this.description = '';
this.detail = `${GlyphChars.Space} ${(commit as GitStashCommit).stashName || commit.shortSha} ${Strings.pad(
GlyphChars.Dot,
1,
1
)} ${commit.formattedDate} ${Strings.pad(GlyphChars.Dot, 1, 1)} ${commit.getFormattedDiffStatus({
compact: true
})}`;
}
else {
this.label = message;
this.description = `${Strings.pad('$(git-commit)', 1, 1)} ${commit.shortSha}`;
this.detail = `${GlyphChars.Space} ${commit.author}, ${commit.formattedDate}${
commit.isFile
? ''
: ` ${Strings.pad(GlyphChars.Dot, 1, 1)} ${commit.getFormattedDiffStatus({ compact: true })}`
}`;
}
}
}
export class ChooseFromBranchesAndTagsQuickPickItem extends CommandQuickPickItem {
constructor(
private readonly repoPath: string,
private readonly placeHolder: string,
private readonly goBackCommand?: CommandQuickPickItem,
item: QuickPickItem = {
label: 'Choose from Branch or Tag History...',
description: `${Strings.pad(GlyphChars.Dash, 2, 2)} shows list of branches and tags`
}
) {
super(item, undefined, undefined);
}
async execute(
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
): Promise<CommandQuickPickItem | BranchOrTagQuickPickItem | undefined> {
const progressCancellation = BranchesAndTagsQuickPick.showProgress(this.placeHolder);
try {
const [branches, tags] = await Promise.all([
Container.git.getBranches(this.repoPath),
Container.git.getTags(this.repoPath)
]);
if (progressCancellation.token.isCancellationRequested) return undefined;
return BranchesAndTagsQuickPick.show(branches, tags, this.placeHolder, {
progressCancellation: progressCancellation,
goBackCommand: this.goBackCommand
});
}
finally {
progressCancellation.cancel();
}
}
}
export class KeyCommandQuickPickItem extends CommandQuickPickItem {
constructor(command: Commands, args?: any[]) {
super({ label: '', description: '' } as QuickPickItem, command, args);
}
}
export class MessageQuickPickItem extends CommandQuickPickItem {
constructor(message: string) {
super({ label: message, description: '' } as QuickPickItem);
}
}
export class OpenFileCommandQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly uri: Uri,
item: QuickPickItem
) {
super(item, undefined, undefined);
}
async execute(options?: TextDocumentShowOptions): Promise<TextEditor | undefined> {
return openEditor(this.uri, options);
}
// onDidSelect(): Promise<{} | undefined> {
// return this.execute({
// preserveFocus: true,
// preview: true
// });
// }
onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute({
preserveFocus: true,
preview: false
});
}
}
export class OpenFilesCommandQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly uris: Uri[],
item: QuickPickItem
) {
super(item, undefined, undefined);
}
async execute(
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
): Promise<{} | undefined> {
for (const uri of this.uris) {
await openEditor(uri, options);
}
return undefined;
}
async onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute({
preserveFocus: true,
preview: false
});
}
}
export class ShowCommitInResultsQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly commit: GitLogCommit,
item: QuickPickItem = {
label: 'Show in Results',
description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays commit in the GitLens Results explorer`
}
) {
super(item, undefined, undefined);
}
async execute(
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
): Promise<{} | undefined> {
Container.resultsExplorer.showCommitInResults(this.commit);
return undefined;
}
}
export class ShowCommitsInResultsQuickPickItem extends CommandQuickPickItem {
constructor(
public readonly results: GitLog,
public readonly resultsLabel: string | { label: string; resultsType?: { singular: string; plural: string } },
item: QuickPickItem = {
label: 'Show in Results',
description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays commits in the GitLens Results explorer`
}
) {
super(item, undefined, undefined);
}
async execute(
options: TextDocumentShowOptions = { preserveFocus: false, preview: false }
): Promise<{} | undefined> {
Container.resultsExplorer.showCommitsInResults(this.results, this.resultsLabel);
return undefined;
}
}
export class ShowCommitsSearchInResultsQuickPickItem extends ShowCommitsInResultsQuickPickItem {
constructor(
public readonly results: GitLog,
public readonly search: string,
item: QuickPickItem = {
label: 'Show in Results',
description: `${Strings.pad(GlyphChars.Dash, 2, 2)} displays results in the GitLens Results explorer`
}
) {
super(results, { label: search }, item);
}
}