Переглянути джерело

Adds ability to choose a stash for file revisions

main
Eric Amodio 2 роки тому
джерело
коміт
0da1c30c8c
5 змінених файлів з 242 додано та 51 видалено
  1. +9
    -4
      src/commands/diffWithRevision.ts
  2. +38
    -14
      src/commands/diffWithRevisionFrom.ts
  3. +12
    -4
      src/commands/openFileAtRevision.ts
  4. +44
    -26
      src/commands/openFileAtRevisionFrom.ts
  5. +139
    -3
      src/quickpicks/commitPicker.ts

+ 9
- 4
src/commands/diffWithRevision.ts Переглянути файл

@ -10,6 +10,7 @@ import { CommandQuickPickItem, CommitPicker } from '../quickpicks';
import { Strings } from '../system';
import { ActiveEditorCommand, command, Commands, executeCommand, getCommandUri } from './common';
import { DiffWithCommandArgs } from './diffWith';
import { DiffWithRevisionFromCommandArgs } from './diffWithRevisionFrom';
export interface DiffWithRevisionCommandArgs {
line?: number;
@ -70,10 +71,14 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
showOptions: args!.showOptions,
}));
},
showOtherReferences: CommandQuickPickItem.fromCommand(
'Choose a branch or tag...',
Commands.DiffWithRevisionFrom,
),
showOtherReferences: [
CommandQuickPickItem.fromCommand('Choose a Branch or Tag...', Commands.DiffWithRevisionFrom),
CommandQuickPickItem.fromCommand<DiffWithRevisionFromCommandArgs>(
'Choose a Stash...',
Commands.DiffWithRevisionFrom,
{ stash: true },
),
],
},
);
if (pick == null) return;

+ 38
- 14
src/commands/diffWithRevisionFrom.ts Переглянути файл

@ -6,7 +6,7 @@ import { Container } from '../container';
import { GitReference, GitRevision } from '../git/git';
import { GitUri } from '../git/gitUri';
import { Messages } from '../messages';
import { ReferencePicker } from '../quickpicks';
import { ReferencePicker, StashPicker } from '../quickpicks';
import { Strings } from '../system';
import { ActiveEditorCommand, command, Commands, executeCommand, getCommandUri } from './common';
import { DiffWithCommandArgs } from './diffWith';
@ -14,6 +14,7 @@ import { DiffWithCommandArgs } from './diffWith';
export interface DiffWithRevisionFromCommandArgs {
line?: number;
showOptions?: TextDocumentShowOptions;
stash?: boolean;
}
@command()
@ -38,19 +39,42 @@ export class DiffWithRevisionFromCommand extends ActiveEditorCommand {
args.line = editor?.selection.active.line ?? 0;
}
const title = `Open Changes with Branch or Tag${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await ReferencePicker.show(
gitUri.repoPath,
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a branch or tag to compare with',
{
allowEnteringRefs: true,
// checkmarks: false,
},
);
if (pick == null) return;
let ref;
let sha;
if (args?.stash) {
const fileName = Strings.normalizePath(paths.relative(gitUri.repoPath, gitUri.fsPath));
const title = `Open Changes with Stash${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await StashPicker.show(
Container.instance.git.getStash(gitUri.repoPath),
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a stash to compare with',
{
empty: `No stashes with '${gitUri.getFormattedFileName()}' found`,
filter: c => c.files.some(f => f.fileName === fileName || f.originalFileName === fileName),
},
);
if (pick == null) return;
ref = pick.ref;
sha = ref;
} else {
const title = `Open Changes with Branch or Tag${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await ReferencePicker.show(
gitUri.repoPath,
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a branch or tag to compare with',
{
allowEnteringRefs: true,
// checkmarks: false,
},
);
if (pick == null) return;
ref = pick.ref;
sha = GitReference.isBranch(pick) && pick.remote ? `remotes/${ref}` : ref;
}
const ref = pick.ref;
if (ref == null) return;
let renamedUri: Uri | undefined;
@ -70,7 +94,7 @@ export class DiffWithRevisionFromCommand extends ActiveEditorCommand {
void (await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
repoPath: gitUri.repoPath,
lhs: {
sha: GitReference.isBranchan class="p">(pick) && pick.remote ? `remotes/${ref}` : ref,
sha: sha,
uri: renamedUri ?? gitUri,
title: renamedTitle ?? `${paths.basename(gitUri.fsPath)} (${GitRevision.shorten(ref)})`,
},

+ 12
- 4
src/commands/openFileAtRevision.ts Переглянути файл

@ -11,6 +11,7 @@ import { CommandQuickPickItem, CommitPicker } from '../quickpicks';
import { Strings } from '../system';
import { ActiveEditorCommand, command, CommandContext, Commands, getCommandUri } from './common';
import { GitActions } from './gitCommands';
import { OpenFileAtRevisionFromCommandArgs } from './openFileAtRevisionFrom';
export interface OpenFileAtRevisionCommandArgs {
revisionUri?: Uri;
@ -115,10 +116,17 @@ export class OpenFileAtRevisionCommand extends ActiveEditorCommand {
preview: false,
}));
},
showOtherReferences: CommandQuickPickItem.fromCommand(
'Choose a branch or tag...',
Commands.OpenFileAtRevisionFrom,
),
showOtherReferences: [
CommandQuickPickItem.fromCommand(
'Choose a Branch or Tag...',
Commands.OpenFileAtRevisionFrom,
),
CommandQuickPickItem.fromCommand<OpenFileAtRevisionFromCommandArgs>(
'Choose a Stash...',
Commands.OpenFileAtRevisionFrom,
{ stash: true },
),
],
},
);
if (pick == null) return;

+ 44
- 26
src/commands/openFileAtRevisionFrom.ts Переглянути файл

@ -1,11 +1,13 @@
'use strict';
import * as paths from 'path';
import { TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { FileAnnotationType } from '../configuration';
import { GlyphChars, quickPickTitleMaxChars } from '../constants';
import { Container } from '../container';
import { GitReference } from '../git/git';
import { GitUri } from '../git/gitUri';
import { Messages } from '../messages';
import { ReferencePicker } from '../quickpicks';
import { ReferencePicker, StashPicker } from '../quickpicks';
import { Strings } from '../system';
import { ActiveEditorCommand, command, Commands, getCommandUri } from './common';
import { GitActions } from './gitCommands';
@ -16,6 +18,7 @@ export interface OpenFileAtRevisionFromCommandArgs {
line?: number;
showOptions?: TextDocumentShowOptions;
annotationType?: FileAnnotationType;
stash?: boolean;
}
@command()
@ -40,33 +43,48 @@ export class OpenFileAtRevisionFromCommand extends ActiveEditorCommand {
}
if (args.reference == null) {
const title = `Open File at Branch or Tag${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await ReferencePicker.show(
gitUri.repoPath,
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a branch or tag to open the file revision from',
{
allowEnteringRefs: true,
keys: ['right', 'alt+right', 'ctrl+right'],
onDidPressKey: async (key, quickpick) => {
const [item] = quickpick.activeItems;
if (item != null) {
void (await GitActions.Commit.openFileAtRevision(
GitUri.toRevisionUri(item.ref, gitUri.fsPath, gitUri.repoPath!),
{
annotationType: args!.annotationType,
line: args!.line,
preserveFocus: true,
preview: false,
},
));
}
if (args?.stash) {
const fileName = Strings.normalizePath(paths.relative(gitUri.repoPath, gitUri.fsPath));
const title = `Open Changes with Stash${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await StashPicker.show(
Container.instance.git.getStash(gitUri.repoPath),
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a stash to compare with',
{ filter: c => c.files.some(f => f.fileName === fileName || f.originalFileName === fileName) },
);
if (pick == null) return;
args.reference = pick;
} else {
const title = `Open File at Branch or Tag${Strings.pad(GlyphChars.Dot, 2, 2)}`;
const pick = await ReferencePicker.show(
gitUri.repoPath,
`${title}${gitUri.getFormattedFileName({ truncateTo: quickPickTitleMaxChars - title.length })}`,
'Choose a branch or tag to open the file revision from',
{
allowEnteringRefs: true,
keys: ['right', 'alt+right', 'ctrl+right'],
onDidPressKey: async (key, quickpick) => {
const [item] = quickpick.activeItems;
if (item != null) {
void (await GitActions.Commit.openFileAtRevision(
GitUri.toRevisionUri(item.ref, gitUri.fsPath, gitUri.repoPath!),
{
annotationType: args!.annotationType,
line: args!.line,
preserveFocus: true,
preview: false,
},
));
}
},
},
},
);
if (pick == null) return;
);
if (pick == null) return;
args.reference = pick;
args.reference = pick;
}
}
void (await GitActions.Commit.openFileAtRevision(

+ 139
- 3
src/quickpicks/commitPicker.ts Переглянути файл

@ -2,7 +2,7 @@
import { Disposable, window } from 'vscode';
import { configuration } from '../configuration';
import { Container } from '../container';
import { GitLog, GitLogCommit } from '../git/git';
import { GitLog, GitLogCommit, GitStash, GitStashCommit } from '../git/git';
import { KeyboardScope, Keys } from '../keyboard';
import {
CommandQuickPickItem,
@ -22,7 +22,7 @@ export namespace CommitPicker {
picked?: string;
keys?: Keys[];
onDidPressKey?(key: Keys, item: CommitQuickPickItem): void | Promise<void>;
showOtherReferences?: CommandQuickPickItem;
showOtherReferences?: CommandQuickPickItem[];
},
): Promise<GitLogCommit | undefined> {
const quickpick = window.createQuickPick<CommandQuickPickItem | CommitQuickPickItem | DirectiveQuickPickItem>();
@ -55,7 +55,7 @@ export namespace CommitPicker {
return log == null
? [DirectiveQuickPickItem.create(Directive.Cancel)]
: [
...(options?.showOtherReferences != null ? [options?.showOtherReferences] : []),
...(options?.showOtherReferences ?? []),
...Iterables.map(log.commits.values(), commit =>
CommitQuickPickItem.create(commit, options?.picked === commit.ref, {
compact: true,
@ -181,3 +181,139 @@ export namespace CommitPicker {
}
}
}
export namespace StashPicker {
export async function show(
stash: GitStash | undefined | Promise<GitStash | undefined>,
title: string,
placeholder: string,
options?: {
empty?: string;
filter?: (c: GitStashCommit) => boolean;
keys?: Keys[];
onDidPressKey?(key: Keys, item: CommitQuickPickItem<GitStashCommit>): void | Promise<void>;
picked?: string;
showOtherReferences?: CommandQuickPickItem[];
},
): Promise<GitStashCommit | undefined> {
const quickpick = window.createQuickPick<
CommandQuickPickItem | CommitQuickPickItem<GitStashCommit> | DirectiveQuickPickItem
>();
quickpick.ignoreFocusOut = getQuickPickIgnoreFocusOut();
quickpick.title = title;
quickpick.placeholder = placeholder;
quickpick.matchOnDescription = true;
quickpick.matchOnDetail = true;
if (Promises.is(stash)) {
quickpick.busy = true;
quickpick.enabled = false;
quickpick.show();
stash = await stash;
}
if (stash != null) {
quickpick.items = [
...(options?.showOtherReferences ?? []),
...Iterables.map(
options?.filter != null
? Iterables.filter(stash.commits.values(), options.filter)
: stash.commits.values(),
commit =>
CommitQuickPickItem.create(commit, options?.picked === commit.ref, {
compact: true,
icon: true,
}),
),
];
}
if (stash == null || quickpick.items.length <= (options?.showOtherReferences?.length ?? 0)) {
quickpick.placeholder = stash == null ? 'No stashes found' : options?.empty ?? `No matching stashes found`;
quickpick.items = [DirectiveQuickPickItem.create(Directive.Cancel)];
}
if (options?.picked) {
quickpick.activeItems = quickpick.items.filter(i => (CommandQuickPickItem.is(i) ? false : i.picked));
}
const disposables: Disposable[] = [];
let scope: KeyboardScope | undefined;
if (options?.keys != null && options.keys.length !== 0 && options?.onDidPressKey !== null) {
scope = Container.instance.keyboard.createScope(
Object.fromEntries(
options.keys.map(key => [
key,
{
onDidPressKey: key => {
if (quickpick.activeItems.length !== 0) {
const [item] = quickpick.activeItems;
if (
item != null &&
!DirectiveQuickPickItem.is(item) &&
!CommandQuickPickItem.is(item)
) {
void options.onDidPressKey!(key, item);
}
}
},
},
]),
),
);
void scope.start();
disposables.push(scope);
}
try {
const pick = await new Promise<
CommandQuickPickItem | CommitQuickPickItem<GitStashCommit> | DirectiveQuickPickItem | undefined
>(resolve => {
disposables.push(
quickpick.onDidHide(() => resolve(undefined)),
quickpick.onDidAccept(() => {
if (quickpick.activeItems.length !== 0) {
const [item] = quickpick.activeItems;
if (DirectiveQuickPickItem.is(item)) {
resolve(undefined);
return;
}
resolve(item);
}
}),
quickpick.onDidChangeValue(async e => {
if (scope == null) return;
// Pause the left/right keyboard commands if there is a value, otherwise the left/right arrows won't work in the input properly
if (e.length !== 0) {
await scope.pause(['left', 'right']);
} else {
await scope.resume();
}
}),
);
quickpick.busy = false;
quickpick.enabled = true;
quickpick.show();
});
if (pick == null || DirectiveQuickPickItem.is(pick)) return undefined;
if (pick instanceof CommandQuickPickItem) {
void (await pick.execute());
return undefined;
}
return pick.item;
} finally {
quickpick.dispose();
disposables.forEach(d => d.dispose());
}
}
}

Завантаження…
Відмінити
Зберегти