Browse Source

Reworks branches/tags quickpick

main
Eric Amodio 6 years ago
parent
commit
87e214c51b
14 changed files with 210 additions and 175 deletions
  1. +1
    -1
      src/commands/diffWithRevision.ts
  2. +13
    -15
      src/commands/openBranchInRemote.ts
  3. +15
    -20
      src/commands/openFileInRemote.ts
  4. +1
    -1
      src/commands/openFileRevision.ts
  5. +9
    -8
      src/commands/showQuickBranchHistory.ts
  6. +1
    -1
      src/commands/showQuickFileHistory.ts
  7. +0
    -1
      src/quickpicks.ts
  8. +148
    -71
      src/quickpicks/branchesAndTagsQuickPick.ts
  9. +0
    -43
      src/quickpicks/branchesQuickPick.ts
  10. +2
    -2
      src/quickpicks/commonQuickPicks.ts
  11. +9
    -5
      src/views/nodes/fileHistoryTrackerNode.ts
  12. +9
    -5
      src/views/nodes/lineHistoryTrackerNode.ts
  13. +1
    -1
      src/views/nodes/statusUpstreamNode.ts
  14. +1
    -1
      src/views/nodes/tagsNode.ts

+ 1
- 1
src/commands/diffWithRevision.ts View File

@ -129,7 +129,7 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
return commands.executeCommand(Commands.DiffWithRevision, gitUri, {
...args,
branchOrTag: branchOrTag.branchOrTag,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as DiffWithRevisionCommandArgs);
}

+ 13
- 15
src/commands/openBranchInRemote.ts View File

@ -4,7 +4,7 @@ import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { BranchesQuickPick, CommandQuickPickItem } from '../quickpicks';
import { BranchesAndTagsQuickPick, CommandQuickPickItem } from '../quickpicks';
import {
ActiveEditorCommand,
command,
@ -53,21 +53,19 @@ export class OpenBranchInRemoteCommand extends ActiveEditorCommand {
if (args.branch === undefined) {
args = { ...args };
const branches = (await Container.git.getBranches(repoPath)).filter(b => b.tracking !== undefined);
if (branches.length > 1) {
const pick = await BranchesQuickPick.show(
branches,
`Open which branch on remote${GlyphChars.Ellipsis}`
);
if (pick === undefined) return undefined;
const pick = await new BranchesAndTagsQuickPick(repoPath).show(
`Open which branch on remote${GlyphChars.Ellipsis}`,
{
autoPick: true,
filters: {
branches: b => b.tracking !== undefined
},
include: 'branches'
}
);
if (pick === undefined || pick instanceof CommandQuickPickItem) return undefined;
if (pick instanceof CommandQuickPickItem) return undefined;
args.branch = pick.branch.name;
}
else if (branches.length === 1) {
args.branch = branches[0].name;
}
args.branch = pick.item.name;
}
const remotes = await Container.git.getRemotes(repoPath);

+ 15
- 20
src/commands/openFileInRemote.ts View File

@ -1,10 +1,11 @@
'use strict';
import { __await } from 'tslib';
import { commands, Range, TextEditor, Uri, window } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { BranchesQuickPick, CommandQuickPickItem } from '../quickpicks';
import { BranchesAndTagsQuickPick, CommandQuickPickItem } from '../quickpicks';
import {
ActiveEditorCommand,
command,
@ -54,27 +55,21 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
if (args.branch === undefined) {
const branch = await Container.git.getBranch(gitUri.repoPath);
if (branch === undefined || branch.tracking === undefined) {
const branches = (await Container.git.getBranches(gitUri.repoPath)).filter(
b => b.tracking !== undefined
const pick = await new BranchesAndTagsQuickPick(gitUri.repoPath).show(
args.clipboard
? `Copy url for ${gitUri.getRelativePath()} to clipboard for which branch${GlyphChars.Ellipsis}`
: `Open ${gitUri.getRelativePath()} on remote for which branch${GlyphChars.Ellipsis}`,
{
autoPick: true,
filters: {
branches: b => b.tracking !== undefined
},
include: 'branches'
}
);
if (branches.length > 1) {
const pick = await BranchesQuickPick.show(
branches,
args.clipboard
? `Copy url for ${gitUri.getRelativePath()} to clipboard for which branch${
GlyphChars.Ellipsis
}`
: `Open ${gitUri.getRelativePath()} on remote for which branch${GlyphChars.Ellipsis}`
);
if (pick === undefined) return undefined;
if (pick === undefined || pick instanceof CommandQuickPickItem) return undefined;
if (pick instanceof CommandQuickPickItem) return undefined;
args.branch = pick.branch.name;
}
else if (branches.length === 1) {
args.branch = branches[0].name;
}
args.branch = pick.item.name;
}
else {
args.branch = branch.name;

+ 1
- 1
src/commands/openFileRevision.ts View File

@ -157,7 +157,7 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
return commands.executeCommand(Commands.OpenFileRevision, gitUri, {
...args,
branchOrTag: branchOrTag.branchOrTag,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as OpenFileRevisionCommandArgs);
}

+ 9
- 8
src/commands/showQuickBranchHistory.ts View File

@ -5,7 +5,7 @@ import { Container } from '../container';
import { GitLog, GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { BranchesQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickpicks';
import { BranchesAndTagsQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickpicks';
import { Strings } from '../system';
import { ActiveEditorCachedCommand, command, Commands, getCommandUri, getRepoPathOrActiveOrPrompt } from './common';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
@ -46,8 +46,6 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
if (!repoPath) return undefined;
if (args.branch === undefined) {
const branches = await Container.git.getBranches(repoPath);
let goBackCommand;
if (!(await Container.git.getRepoPathOrActive(uri, editor))) {
goBackCommand = new CommandQuickPickItem(
@ -60,14 +58,17 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
);
}
const pick = await BranchesQuickPick.show(branches, `Show history for branch${GlyphChars.Ellipsis}`, {
goBackCommand: goBackCommand
});
const pick = await new BranchesAndTagsQuickPick(repoPath).show(
`Show history for branch${GlyphChars.Ellipsis}`,
{
goBack: goBackCommand,
include: 'branches'
}
);
if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) return pick.execute();
args.branch = pick.branch.name;
args.branch = pick.item.name;
if (args.branch === undefined) return undefined;
progressCancellation = BranchHistoryQuickPick.showProgress(args.branch);

+ 1
- 1
src/commands/showQuickFileHistory.ts View File

@ -172,7 +172,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
return commands.executeCommand(Commands.ShowQuickFileHistory, gitUri, {
...args,
log: undefined,
branchOrTag: branchOrTag.branchOrTag,
branchOrTag: branchOrTag.item,
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs);
}

+ 0
- 1
src/quickpicks.ts View File

@ -1,7 +1,6 @@
'use strict';
export * from './quickpicks/branchesAndTagsQuickPick';
export * from './quickpicks/branchesQuickPick';
export * from './quickpicks/branchHistoryQuickPick';
export * from './quickpicks/commitFileQuickPick';
export * from './quickpicks/commitQuickPick';

+ 148
- 71
src/quickpicks/branchesAndTagsQuickPick.ts View File

@ -3,44 +3,81 @@ import { CancellationToken, CancellationTokenSource, QuickPickItem, QuickPickOpt
import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitBranch, GitTag } from '../git/gitService';
import { KeyNoopCommand } from '../keyboard';
import { Functions, Iterables } from '../system';
import { Functions } from '../system';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './commonQuickPicks';
export class BranchOrTagQuickPickItem implements QuickPickItem {
export class BranchQuickPickItem implements QuickPickItem {
label: string;
description: string;
detail: string | undefined;
constructor(
public readonly branchOrTag: GitBranch | GitTag,
public readonly branch: GitBranch,
checked?: boolean
) {
if (branchOrTag instanceof GitBranch) {
this.label = `${
checked === true || (checked === undefined && branchOrTag.current)
? `$(check)${GlyphChars.Space}`
: GlyphChars.Space.repeat(4)
} ${branchOrTag.name}`;
this.description = branchOrTag.remote ? `${GlyphChars.Space.repeat(2)} remote branch` : '';
}
else {
this.label = `${GlyphChars.Space.repeat(4)} ${branchOrTag.name}`;
this.description = `${GlyphChars.Space.repeat(2)} tag`;
}
checked = checked || (checked === undefined && branch.current);
this.label = `${checked ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${branch.name}`;
this.description = branch.remote ? `${GlyphChars.Space.repeat(2)} remote branch` : '';
}
get current() {
return this.branchOrTag instanceof GitBranch ? this.branchOrTag.current : false;
return this.branch.current;
}
get item() {
return this.branch;
}
get name() {
return this.branchOrTag.name;
return this.branch.name;
}
get remote() {
return this.branchOrTag instanceof GitBranch && this.branchOrTag.remote;
return this.branch.remote;
}
}
export class TagQuickPickItem implements QuickPickItem {
label: string;
description: string;
detail: string | undefined;
constructor(
public readonly tag: GitBranch | GitTag,
checked?: boolean
) {
this.label = `${checked ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${tag.name}`;
this.description = `${GlyphChars.Space.repeat(2)} tag`;
}
get current() {
return false;
}
get item() {
return this.tag;
}
get name() {
return this.tag.name;
}
get remote() {
return false;
}
}
export type BranchOrTagQuickPickItem = BranchQuickPickItem | TagQuickPickItem;
export interface BranchesAndTagsQuickPickOptions {
autoPick?: boolean;
checked?: string;
filters?: {
branches?(branch: GitBranch): boolean;
tags?(tag: GitTag): boolean;
};
goBack?: CommandQuickPickItem;
include?: 'branches' | 'tags' | 'all';
}
export class BranchesAndTagsQuickPick {
@ -50,75 +87,115 @@ export class BranchesAndTagsQuickPick {
async show(
placeHolder: string,
options: { checked?: string; goBack?: CommandQuickPickItem } = {}
options: BranchesAndTagsQuickPickOptions = {}
): Promise<BranchOrTagQuickPickItem | CommandQuickPickItem | undefined> {
const cancellation = new CancellationTokenSource();
let scope;
if (options.goBack) {
scope = await Container.keyboard.beginScope({ left: options.goBack });
}
let autoPick;
try {
const items = this.getItems(options, cancellation.token);
const scope = await Container.keyboard.beginScope({ left: options.goBack || KeyNoopCommand });
let items = this.getItems(options, cancellation.token);
if (options.autoPick) {
items = items.then(itms => {
if (itms.length <= 1) {
autoPick = itms[0];
cancellation.cancel();
}
return itms;
});
}
const pick = await window.showQuickPick(items, {
placeHolder: placeHolder,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions);
let pick = await window.showQuickPick(
items,
{
placeHolder: placeHolder,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions,
cancellation.token
);
if (pick === undefined && autoPick !== undefined) {
pick = autoPick;
}
if (pick === undefined) {
cancellation.cancel();
}
await scope.dispose();
return pick;
}
finally {
if (scope !== undefined) {
await scope.dispose();
}
cancellation.dispose();
}
}
private async getItems(
options: { checked?: string; goBack?: CommandQuickPickItem } = {},
token: CancellationToken
) {
const result = await Functions.cancellable(
Promise.all([Container.git.getBranches(this.repoPath), Container.git.getTags(this.repoPath)]),
token
);
if (result === undefined || token.isCancellationRequested) return [];
const [branches, tags] = result;
const items = [
...Iterables.filterMap(
branches,
b =>
!b.remote
? new BranchOrTagQuickPickItem(
b,
options.checked !== undefined ? b.name === options.checked : undefined
)
: undefined
),
...Iterables.filterMap(
branches,
b =>
b.remote
? new BranchOrTagQuickPickItem(
b,
options.checked !== undefined ? b.name === options.checked : undefined
)
: undefined
),
...tags.map(
t =>
new BranchOrTagQuickPickItem(
t,
options.checked !== undefined ? t.name === options.checked : undefined
)
)
] as (BranchOrTagQuickPickItem | CommandQuickPickItem)[];
if (options.goBack !== undefined) {
items.splice(0, 0, options.goBack);
private async getItems(options: BranchesAndTagsQuickPickOptions, token: CancellationToken) {
const { checked, filters, goBack, include } = { include: 'all', ...options };
let branches;
let tags;
switch (include) {
case 'branches': {
const result = await Functions.cancellable(Container.git.getBranches(this.repoPath), token);
if (result === undefined || token.isCancellationRequested) return [];
branches = result;
break;
}
case 'tags': {
const result = await Functions.cancellable(Container.git.getTags(this.repoPath), token);
if (result === undefined || token.isCancellationRequested) return [];
tags = result;
break;
}
default: {
const result = await Functions.cancellable(
Promise.all([Container.git.getBranches(this.repoPath), Container.git.getTags(this.repoPath)]),
token
);
if (result === undefined || token.isCancellationRequested) return [];
[branches, tags] = result;
break;
}
}
const items: (BranchOrTagQuickPickItem | CommandQuickPickItem)[] = [];
if (branches !== undefined) {
const filter =
filters !== undefined && typeof filters.branches === 'function' ? filters.branches : undefined;
branches.sort((a, b) => (b.remote ? -1 : 1) - (a.remote ? -1 : 1) || a.name.localeCompare(b.name));
for (const b of branches) {
if (filter !== undefined && !filter(b)) continue;
items.push(new BranchQuickPickItem(b, checked !== undefined ? b.name === checked : undefined));
}
}
if (tags !== undefined) {
const filter = filters !== undefined && typeof filters.tags === 'function' ? filters.tags : undefined;
tags.sort((a, b) => a.name.localeCompare(b.name));
for (const t of tags) {
if (filter !== undefined && !filter(t)) continue;
items.push(new TagQuickPickItem(t, checked !== undefined ? t.name === checked : undefined));
}
}
if (goBack !== undefined) {
items.splice(0, 0, goBack);
}
return items;

+ 0
- 43
src/quickpicks/branchesQuickPick.ts View File

@ -1,43 +0,0 @@
'use strict';
import { QuickPickItem, QuickPickOptions, window } from 'vscode';
import { GlyphChars } from '../constants';
import { GitBranch } from '../git/gitService';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './commonQuickPicks';
export class BranchQuickPickItem implements QuickPickItem {
label: string;
description: string;
detail: string | undefined;
constructor(
public readonly branch: GitBranch
) {
this.label = `${branch.current ? `$(check)${GlyphChars.Space}` : GlyphChars.Space.repeat(4)} ${branch.name}`;
this.description = branch.remote ? `${GlyphChars.Space.repeat(2)} remote branch` : '';
}
}
export class BranchesQuickPick {
static async show(
branches: GitBranch[],
placeHolder: string,
options: { goBackCommand?: CommandQuickPickItem } = {}
): Promise<BranchQuickPickItem | CommandQuickPickItem | undefined> {
const items = branches.map(b => new BranchQuickPickItem(b)) as (BranchQuickPickItem | CommandQuickPickItem)[];
if (options.goBackCommand !== undefined) {
items.splice(0, 0, options.goBackCommand);
}
// const scope = await Container.keyboard.beginScope({ left: goBackCommand });
const pick = await window.showQuickPick(items, {
placeHolder: placeHolder,
ignoreFocusOut: getQuickPickIgnoreFocusOut()
} as QuickPickOptions);
// await scope.dispose();
return pick;
}
}

+ 2
- 2
src/quickpicks/commonQuickPicks.ts View File

@ -16,7 +16,7 @@ import { Container } from '../container';
import { GitLog, GitLogCommit, GitStashCommit } from '../git/gitService';
import { KeyMapping, Keys } from '../keyboard';
import { Strings } from '../system';
import { BranchesAndTagsQuickPick, BranchOrTagQuickPickItem } from './branchesAndTagsQuickPick';
import { BranchesAndTagsQuickPick, BranchQuickPickItem, TagQuickPickItem } from './branchesAndTagsQuickPick';
export function getQuickPickIgnoreFocusOut() {
return !configuration.get<boolean>(configuration.name('advanced')('quickPick')('closeOnFocusOut').value);
@ -145,7 +145,7 @@ export class ChooseFromBranchesAndTagsQuickPickItem extends CommandQuickPickItem
super(item, undefined, undefined);
}
execute(): Promise<CommandQuickPickItem | BranchOrTagQuickPickItem | undefined> {
execute(): Promise<CommandQuickPickItem | BranchQuickPickItem | TagQuickPickItem | undefined> {
return new BranchesAndTagsQuickPick(this.repoPath).show(this.placeHolder, { goBack: this._goBack });
}
}

+ 9
- 5
src/views/nodes/fileHistoryTrackerNode.ts View File

@ -2,9 +2,10 @@
import * as paths from 'path';
import { Disposable, TextEditor, TreeItem, TreeItemCollapsibleState, Uri, window } from 'vscode';
import { UriComparer } from '../../comparers';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitCommitish, GitUri } from '../../git/gitService';
import { BranchesAndTagsQuickPick, BranchOrTagQuickPickItem } from '../../quickpicks';
import { BranchesAndTagsQuickPick, CommandQuickPickItem } from '../../quickpicks';
import { debug, Functions, gate, log } from '../../system';
import { FileHistoryView } from '../fileHistoryView';
import { MessageNode } from './common';
@ -58,10 +59,13 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode
@gate()
@log()
async changeBase() {
const pick = await new BranchesAndTagsQuickPick(this.uri.repoPath!).show('Change the file history base to...', {
checked: this._base
});
if (pick === undefined || !(pick instanceof BranchOrTagQuickPickItem)) return;
const pick = await new BranchesAndTagsQuickPick(this.uri.repoPath!).show(
`Change the file history base to${GlyphChars.Ellipsis}`,
{
checked: this._base
}
);
if (pick === undefined || pick instanceof CommandQuickPickItem) return;
this._base = pick.current ? undefined : pick.name;
if (this._child === undefined) return;

+ 9
- 5
src/views/nodes/lineHistoryTrackerNode.ts View File

@ -1,9 +1,10 @@
'use strict';
import { Disposable, Selection, TreeItem, TreeItemCollapsibleState, window } from 'vscode';
import { UriComparer } from '../../comparers';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitCommitish, GitUri } from '../../git/gitService';
import { BranchesAndTagsQuickPick, BranchOrTagQuickPickItem } from '../../quickpicks';
import { BranchesAndTagsQuickPick, CommandQuickPickItem } from '../../quickpicks';
import { debug, Functions, gate, log } from '../../system';
import { LinesChangeEvent } from '../../trackers/gitLineTracker';
import { LineHistoryView } from '../lineHistoryView';
@ -59,10 +60,13 @@ export class LineHistoryTrackerNode extends SubscribeableViewNode
@gate()
@log()
async changeBase() {
const pick = await new BranchesAndTagsQuickPick(this.uri.repoPath!).show('Change the line history base to...', {
checked: this._base
});
if (pick === undefined || !(pick instanceof BranchOrTagQuickPickItem)) return;
const pick = await new BranchesAndTagsQuickPick(this.uri.repoPath!).show(
`Change the line history base to${GlyphChars.Ellipsis}`,
{
checked: this._base
}
);
if (pick === undefined || pick instanceof CommandQuickPickItem) return;
this._base = pick.current ? undefined : pick.name;
if (this._child === undefined) return;

+ 1
- 1
src/views/nodes/statusUpstreamNode.ts View File

@ -51,7 +51,7 @@ export class StatusUpstreamNode extends ViewNode implements PageableViewNode {
}
}
children = [...insertDateMarkers(commits.map(c => new CommitNode(c, this, this.view)), this, 1)];
children = [...insertDateMarkers(Iterables.map(commits, c => new CommitNode(c, this, this.view)), this, 1)];
}
else {
children = [

+ 1
- 1
src/views/nodes/tagsNode.ts View File

@ -29,7 +29,7 @@ export class TagsNode extends ViewNode {
if (tags.length === 0) return [new MessageNode(this, 'No tags could be found.')];
tags.sort((a, b) => a.name.localeCompare(b.name));
const tagNodes = [...tags.map(t => new TagNode(t, this.uri, this, this.view))];
const tagNodes = tags.map(t => new TagNode(t, this.uri, this, this.view));
if (this.view.config.branches.layout === ViewBranchesLayout.List) return tagNodes;
const hierarchy = Arrays.makeHierarchical(

Loading…
Cancel
Save