Adds experimental support for Open in GitHub

This commit is contained in:
Eric Amodio
2017-03-24 01:28:05 -04:00
parent ba69a19eeb
commit 4f84c03275
21 changed files with 399 additions and 43 deletions

View File

@@ -1,10 +1,9 @@
'use strict';
import { Iterables } from '../system';
import { Arrays, Iterables } from '../system';
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands';
import { GitUri, IGitLog } from '../gitService';
import { CommitQuickPickItem } from './gitQuickPicks';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './quickPicks';
import { GitService, GitUri, IGitLog } from '../gitService';
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, OpenRemotesCommandQuickPickItem, showQuickPickProgress } from '../quickPicks';
export class BranchHistoryQuickPick {
@@ -17,9 +16,19 @@ export class BranchHistoryQuickPick {
});
}
static async show(log: IGitLog, uri: GitUri, branch: string, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
static async show(git: GitService, log: IGitLog, uri: GitUri, branch: string, progressCancellation: CancellationTokenSource, goBackCommand?: CommandQuickPickItem, nextPageCommand?: CommandQuickPickItem): Promise<CommitQuickPickItem | CommandQuickPickItem | undefined> {
const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c, ` \u2014 ${c.fileNames}`))) as (CommitQuickPickItem | CommandQuickPickItem)[];
const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${branch} history`
}, Commands.ShowQuickBranchHistory, [uri, branch, log.maxCount, goBackCommand, log]);
const remotes = Arrays.uniqueBy(await git.getRemotes(git.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) {
items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, 'branch', branch, currentCommand));
}
let previousPageCommand: CommandQuickPickItem;
if ((log.truncated || (uri && uri.sha))) {
@@ -42,10 +51,7 @@ export class BranchHistoryQuickPick {
new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }),
branch,
undefined,
new CommandQuickPickItem({
label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${branch} history`
}, Commands.ShowQuickBranchHistory, [uri, branch, log.maxCount, goBackCommand, log])
currentCommand
]));
}

View File

@@ -1,10 +1,9 @@
'use strict';
import { Iterables } from '../system';
import { Arrays, Iterables } from '../system';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands';
import { GitLogCommit, GitService, IGitLog } from '../gitService';
import { CommitWithFileStatusQuickPickItem } from './gitQuickPicks';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFilesCommandQuickPickItem } from './quickPicks';
import { CommandQuickPickItem, CommitWithFileStatusQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFilesCommandQuickPickItem, OpenRemotesCommandQuickPickItem } from '../quickPicks';
import * as moment from 'moment';
import * as path from 'path';
@@ -36,7 +35,7 @@ export class OpenCommitWorkingTreeFilesCommandQuickPickItem extends OpenFilesCom
export class CommitDetailsQuickPick {
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, repoLog?: IGitLog): Promise<CommitWithFileStatusQuickPickItem | CommandQuickPickItem | undefined> {
static async show(git: GitService, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, repoLog?: IGitLog): Promise<CommitWithFileStatusQuickPickItem | CommandQuickPickItem | undefined> {
const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.fileStatuses.map(fs => new CommitWithFileStatusQuickPickItem(commit, fs.fileName, fs.status));
let index = 0;
@@ -51,6 +50,11 @@ export class CommitDetailsQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
}, Commands.CopyMessageToClipboard, [uri, commit.sha, commit.message]));
const remotes = Arrays.uniqueBy(await git.getRemotes(git.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) {
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, 'commit', commit.sha, currentCommand));
}
items.splice(index++, 0, new CommandQuickPickItem({
label: `$(git-compare) Directory Compare with Previous Commit`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha || `${commit.shortSha}^`} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}`
@@ -61,7 +65,6 @@ export class CommitDetailsQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-directory) Working Tree`
}, Commands.DiffDirectory, [uri, commit.sha]));
const added = commit.fileStatuses.filter(_ => _.status === 'A' || _.status === '?').length;
const deleted = commit.fileStatuses.filter(_ => _.status === 'D').length;
const changed = commit.fileStatuses.filter(_ => _.status !== 'A' && _.status !== '?' && _.status !== 'D').length;

View File

@@ -1,9 +1,9 @@
'use strict';
import { Iterables } from '../system';
import { Arrays, Iterables } from '../system';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands';
import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './quickPicks';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenRemotesCommandQuickPickItem } from '../quickPicks';
import * as moment from 'moment';
import * as path from 'path';
@@ -75,7 +75,17 @@ export class CommitFileDetailsQuickPick {
}, Commands.CopyMessageToClipboard, [uri, commit.sha, commit.message]));
items.push(new OpenCommitFileCommandQuickPickItem(commit));
items.push(new OpenCommitWorkingTreeFileCommandQuickPickItem(commit));
if (commit.workingFileName) {
items.push(new OpenCommitWorkingTreeFileCommandQuickPickItem(commit));
}
const remotes = Arrays.uniqueBy(await git.getRemotes(git.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) {
items.push(new OpenRemotesCommandQuickPickItem(remotes, 'file', commit.fileName, commit.sha, undefined, currentCommand));
if (commit.workingFileName) {
items.push(new OpenRemotesCommandQuickPickItem(remotes, 'file', commit.workingFileName, undefined, 'Working File', currentCommand));
}
}
if (commit.workingFileName) {
items.push(new CommandQuickPickItem({

View File

@@ -1,10 +1,9 @@
'use strict';
import { Iterables } from '../system';
import { Arrays, Iterables } from '../system';
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands';
import { GitService, GitUri, IGitLog } from '../gitService';
import { CommitQuickPickItem } from './gitQuickPicks';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './quickPicks';
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, OpenRemotesCommandQuickPickItem, showQuickPickProgress } from '../quickPicks';
import * as path from 'path';
export class FileHistoryQuickPick {
@@ -74,21 +73,28 @@ export class FileHistoryQuickPick {
}
}
const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}`
}, Commands.ShowQuickFileHistory, [uri, log.range, log.maxCount, undefined, log]);
// Only show the full repo option if we are the root
if (!goBackCommand) {
items.splice(index, 0, new CommandQuickPickItem({
items.splice(index++, 0, new CommandQuickPickItem({
label: `$(history) Show Branch History`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows the current branch history`
}, Commands.ShowQuickCurrentBranchHistory,
[
undefined,
new CommandQuickPickItem({
label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}`
}, Commands.ShowQuickFileHistory, [uri, log.range, log.maxCount, undefined, log])
currentCommand
]));
}
const remotes = Arrays.uniqueBy(await git.getRemotes(git.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) {
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, 'file', uri.getRelativePath(), uri.sha, undefined, currentCommand));
}
if (goBackCommand) {
items.splice(0, 0, goBackCommand);
}

139
src/quickPicks/remotes.ts Normal file
View File

@@ -0,0 +1,139 @@
'use strict';
import { QuickPickOptions, window } from 'vscode';
import { GitRemote, HostingProviderOpenType } from '../gitService';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './quickPicks';
import * as path from 'path';
export class OpenRemoteCommandQuickPickItem extends CommandQuickPickItem {
private type: HostingProviderOpenType;
private remote: GitRemote;
constructor(remote: GitRemote, type: HostingProviderOpenType, ...args: string[]);
constructor(remote: GitRemote, type: HostingProviderOpenType, branchOrShaOrFileName: string, fileSha?: string, name?: string) {
if (!name) {
name = `${type[0].toUpperCase()}${type.substring(1)}`;
}
super({
label: `$(link-external) Open ${name} in ${remote.provider.name}`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider.path}`
}, undefined, undefined);
this.type = type;
this.remote = remote;
this.args = [branchOrShaOrFileName, fileSha];
}
async execute(): Promise<{}> {
return this.remote.provider.open(this.type, ...this.args);
}
}
export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
private goBackCommand: CommandQuickPickItem;
private name: string;
private placeHolder: string;
private remotes: GitRemote[];
private type: HostingProviderOpenType;
constructor(remotes: GitRemote[], type: 'branch', branch: string, goBackCommand?: CommandQuickPickItem);
constructor(remotes: GitRemote[], type: 'commit', sha: string, goBackCommand?: CommandQuickPickItem);
constructor(remotes: GitRemote[], type: 'file', fileName: string, sha?: string, name?: string, goBackCommand?: CommandQuickPickItem);
constructor(remotes: GitRemote[], type: HostingProviderOpenType, branchOrShaOrFileName: string, shaOrGoBackCommand?: string | CommandQuickPickItem, name?: string, goBackCommand?: CommandQuickPickItem) {
let fileSha: string;
if (typeof shaOrGoBackCommand === 'string') {
fileSha = shaOrGoBackCommand;
}
else if (!goBackCommand) {
goBackCommand = shaOrGoBackCommand;
}
let description: string;
let placeHolder: string;
switch (type) {
case 'branch':
name = name || 'Branch';
description = `$(git-branch) ${branchOrShaOrFileName}`;
placeHolder = `open ${branchOrShaOrFileName} ${name.toLowerCase()} in\u2026`;
break;
case 'commit':
const shortSha = branchOrShaOrFileName.substring(0, 8);
name = name || 'Commit';
description = `$(git-commit) ${shortSha}`;
placeHolder = `open ${name.toLowerCase()} ${shortSha} in\u2026`;
break;
case 'file':
const fileName = path.basename(branchOrShaOrFileName);
const shortFileSha = (fileSha && fileSha.substring(0, 8)) || '';
const shaSuffix = shortFileSha ? ` \u00a0\u2022\u00a0 ${shortFileSha}` : '';
name = name || 'File';
description = `$(file-text) ${fileName}${shortFileSha ? ` in \u00a0$(git-commit) ${shortFileSha}` : ''}`;
placeHolder = `open ${branchOrShaOrFileName}${shaSuffix} in\u2026`;
break;
}
const remote = remotes[0];
if (remotes.length === 1) {
super({
label: `$(link-external) Open ${name} in ${remote.provider.name}`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider.path} \u00a0\u2022\u00a0 ${description}`
}, undefined, undefined);
}
else {
const provider = remotes.every(_ => _.provider.name === remote.provider.name)
? remote.provider.name
: 'Hosting Provider';
super({
label: `$(link-external) Open ${name} in ${provider}\u2026`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${description}`
}, undefined, undefined);
}
this.goBackCommand = goBackCommand;
this.name = name;
this.placeHolder = placeHolder;
this.remotes = remotes;
this.type = type;
this.args = [branchOrShaOrFileName, fileSha];
}
async execute(): Promise<{}> {
if (this.remotes.length === 1) {
const command = new OpenRemoteCommandQuickPickItem(this.remotes[0], this.type, ...this.args);
return command.execute();
}
const pick = await RemotesQuickPick.show(this.remotes, this.placeHolder, this.type, this.args, this.name, this.goBackCommand);
return pick && pick.execute();
}
}
export class RemotesQuickPick {
static async show(remotes: GitRemote[], placeHolder: string, type: HostingProviderOpenType, args: string[], name: string, goBackCommand?: CommandQuickPickItem): Promise<OpenRemoteCommandQuickPickItem | CommandQuickPickItem | undefined> {
const items = remotes.map(_ => new OpenRemoteCommandQuickPickItem(_, type, ...args, name)) as (OpenRemoteCommandQuickPickItem | CommandQuickPickItem)[];
if (goBackCommand) {
items.splice(0, 0, goBackCommand);
}
// const scope = await Keyboard.instance.beginScope({ left: goBackCommand });
const pick = await window.showQuickPick(items,
{
placeHolder: placeHolder,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions);
if (!pick) return undefined;
// await scope.dispose();
return pick;
}
}