diff --git a/CHANGELOG.md b/CHANGELOG.md index 878fc58..258352f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds a new _reset_ Git command to reset current HEAD to a specified commit - Adds a new _revert_ Git command to revert specific commits - Adds a new _search_ Git command to search for specific commits - - Adds a new _stash_ Git command with sub-commands for _apply_, _drop_, _pop_, and _push_ + - Adds a new _stash_ Git command with sub-commands for _apply_, _drop_, _list_, _pop_, and _push_ - Adds a new _Fetch All & Prune_ option to the _fetch_ Git command - Adds the last fetched on date to the confirmation step of the _fetch_ Git command (when a single repo is selected) - Adds the last fetched on date to the confirmation step of the _pull_ Git command (when a single repo is selected) @@ -59,7 +59,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Changes the _Reset to Commit (via Terminal)_ command to use the _reset_ Git command - Changes the _Revert Commit (via Terminal)_ command to use the _revert_ Git command - Changes all the stash commands to use the new _stash_ Git command -- Changes _Stash All Changes_ commands in the Source Control view to toggle --kee-index appropriately — closes [#698](https://github.com/eamodio/vscode-gitlens/issues/698) +- Changes _Stash All Changes_ commands in the Source Control view to toggle --keep-index appropriately — closes [#698](https://github.com/eamodio/vscode-gitlens/issues/698) - Changes the _Checkout_ command on branches, commits, and tags to use the _switch_ Git command - Changes Ansible files to use document scope for code lens — thanks to [PR #813](https://github.com/eamodio/vscode-gitlens/pull/813) by Ahmadali Shafiee ([@ahmadalli](https://github.com/ahmadalli)) - Renames _Checkout_ command to _Switch_ for branches and tags for better clarity and to align with the new Git 2.23 commands diff --git a/src/commands/git/stash.ts b/src/commands/git/stash.ts index 30024df..3500f70 100644 --- a/src/commands/git/stash.ts +++ b/src/commands/git/stash.ts @@ -1,9 +1,11 @@ 'use strict'; -import { QuickInputButtons, QuickPickItem, Uri, window } from 'vscode'; +/* eslint-disable no-loop-func */ +import { commands, QuickInputButtons, QuickPickItem, Uri, window } from 'vscode'; import { Container } from '../../container'; import { GitStashCommit, GitUri, Repository } from '../../git/gitService'; import { BreakQuickCommand, QuickCommandBase, StepAsyncGenerator, StepSelection, StepState } from '../quickCommand'; import { + CommandQuickPickItem, CommitQuickPickItem, Directive, DirectiveQuickPickItem, @@ -15,6 +17,8 @@ import { Iterables, Strings } from '../../system'; import { GlyphChars } from '../../constants'; import { Logger } from '../../logger'; import { Messages } from '../../messages'; +import { GitCommandsCommandArgs, ShowQuickCommitDetailsCommandArgs } from '../../commands'; +import { Commands } from '../common'; interface ApplyState { subcommand: 'apply'; @@ -30,6 +34,11 @@ interface DropState { flags: string[]; } +interface ListState { + subcommand: 'list'; + repo: Repository; +} + interface PopState { subcommand: 'pop'; repo: Repository; @@ -45,12 +54,13 @@ interface PushState { flags: string[]; } -type State = ApplyState | DropState | PopState | PushState; +type State = ApplyState | DropState | ListState | PopState | PushState; type StashStepState = StepState & { repo: Repository }; const subcommandToSubtitleMap = new Map([ ['apply', 'Apply'], ['drop', 'Drop'], + ['list', 'List'], ['pop', 'Pop'], ['push', 'Push'] ]); @@ -109,7 +119,7 @@ export class StashGitCommand extends QuickCommandBase { } get canConfirm(): boolean { - return this._subcommand !== undefined; + return this._subcommand !== undefined && this._subcommand !== 'list'; } get canSkipConfirm(): boolean { @@ -146,6 +156,12 @@ export class StashGitCommand extends QuickCommandBase { item: 'drop' }, { + label: 'list', + description: 'lists the saved stashes', + picked: state.subcommand === 'list', + item: 'list' + }, + { label: 'pop', description: 'integrates changes from the specified stash into the current branch and deletes the stash', @@ -215,6 +231,9 @@ export class StashGitCommand extends QuickCommandBase { case 'drop': yield* this.drop(state as StashStepState); break; + case 'list': + yield* this.list(state as StashStepState); + break; case 'push': yield* this.push(state as StashStepState); break; @@ -456,6 +475,73 @@ export class StashGitCommand extends QuickCommandBase { return undefined; } + private async *list(state: StashStepState): StepAsyncGenerator { + let pickedStash: GitStashCommit | undefined; + + while (true) { + const stash = await Container.git.getStashList(state.repo.path); + + const step = this.createPickStep>({ + title: `${this.title} ${getSubtitle(state.subcommand)}${Strings.pad(GlyphChars.Dot, 2, 2)}${ + state.repo.formattedName + }`, + placeholder: + stash === undefined + ? `${state.repo.formattedName} has no stashes` + : 'Choose a stash to show in the Repositories view', + matchOnDetail: true, + items: + stash === undefined + ? [ + DirectiveQuickPickItem.create(Directive.Back, true), + DirectiveQuickPickItem.create(Directive.Cancel) + ] + : [ + ...Iterables.map(stash.commits.values(), c => + CommitQuickPickItem.create(c, c.ref === (pickedStash && pickedStash.ref), { + compact: true + }) + ) + ] + }); + const selection: StepSelection = yield step; + + if (!this.canPickStepMoveNext(step, state, selection)) { + break; + } + + state.counter--; + pickedStash = selection[0].item; + + // const node = await Container.repositoriesView.findStashNode(pickedStash); + // if (node !== undefined) { + // Container.repositoriesView.reveal(node, { select: true, expand: true }); + // } + + const gitCommandArgs: GitCommandsCommandArgs = { + command: 'search', + state: { ...state } + }; + + const commandArgs: ShowQuickCommitDetailsCommandArgs = { + sha: pickedStash.sha, + commit: pickedStash, + goBackCommand: new CommandQuickPickItem( + { + label: 'Back', + description: '' + }, + Commands.GitCommands, + [gitCommandArgs] + ) + }; + + void commands.executeCommand(Commands.ShowQuickCommitDetails, pickedStash.toGitUri(), commandArgs); + } + + return undefined; + } + // eslint-disable-next-line @typescript-eslint/require-await private async *push(state: StashStepState): StepAsyncGenerator { while (true) { diff --git a/src/commands/showQuickStashList.ts b/src/commands/showQuickStashList.ts index 2427ee4..78ac762 100644 --- a/src/commands/showQuickStashList.ts +++ b/src/commands/showQuickStashList.ts @@ -1,76 +1,37 @@ 'use strict'; -import { commands, TextEditor, Uri, window } from 'vscode'; -import { GlyphChars } from '../constants'; +import { commands } from 'vscode'; import { Container } from '../container'; -import { Logger } from '../logger'; -import { Messages } from '../messages'; -import { CommandQuickPickItem, StashListQuickPick } from '../quickpicks'; -import { ActiveEditorCachedCommand, command, Commands, getCommandUri, getRepoPathOrActiveOrPrompt } from './common'; -import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails'; +import { CommandQuickPickItem } from '../quickpicks'; +import { Command, command, Commands } from './common'; +import { GitCommandsCommandArgs } from '../commands'; export interface ShowQuickStashListCommandArgs { + repoPath?: string; + goBackCommand?: CommandQuickPickItem; } @command() -export class ShowQuickStashListCommand extends ActiveEditorCachedCommand { +export class ShowQuickStashListCommand extends Command { constructor() { super(Commands.ShowQuickStashList); } - async execute(editor?: TextEditor, uri?: Uri, args?: ShowQuickStashListCommandArgs) { - uri = getCommandUri(uri, editor); - - const repoPath = await getRepoPathOrActiveOrPrompt( - uri, - editor, - `Show stashes for which repository${GlyphChars.Ellipsis}` - ); - if (!repoPath) return undefined; - - const progressCancellation = StashListQuickPick.showProgress('list'); - - try { - const stash = await Container.git.getStashList(repoPath); - if (stash === undefined) return window.showWarningMessage('Unable to show stashes'); - - if (progressCancellation.token.isCancellationRequested) return undefined; + async execute(args?: ShowQuickStashListCommandArgs) { + args = { ...args }; - // Create a command to get back to here - const currentCommandArgs: ShowQuickStashListCommandArgs = { - goBackCommand: args && args.goBackCommand - }; - const currentCommand = new CommandQuickPickItem( - { - label: `go back ${GlyphChars.ArrowBack}`, - description: 'to stashes' - }, - Commands.ShowQuickStashList, - [uri, currentCommandArgs] - ); - - const pick = await StashListQuickPick.show( - stash, - 'list', - progressCancellation, - args && args.goBackCommand, - currentCommand - ); - if (pick === undefined) return undefined; - - if (pick instanceof CommandQuickPickItem) return pick.execute(); - - const commandArgs: ShowQuickCommitDetailsCommandArgs = { - commit: pick.item, - sha: pick.item.sha, - goBackCommand: currentCommand - }; - return commands.executeCommand(Commands.ShowQuickCommitDetails, pick.item.toGitUri(), commandArgs); - } catch (ex) { - Logger.error(ex, 'ShowQuickStashListCommand'); - return Messages.showGenericErrorMessage('Unable to show stashes'); - } finally { - progressCancellation.cancel(); + let repo; + if (args.repoPath !== undefined) { + repo = await Container.git.getRepository(args.repoPath); } + + const gitCommandArgs: GitCommandsCommandArgs = { + command: 'stash', + state: { + subcommand: 'list', + repo: repo + } + }; + return commands.executeCommand(Commands.GitCommands, gitCommandArgs); } } diff --git a/src/quickpicks.ts b/src/quickpicks.ts index 3cc2469..97e0b21 100644 --- a/src/quickpicks.ts +++ b/src/quickpicks.ts @@ -13,4 +13,3 @@ export * from './quickpicks/referencesQuickPick'; export * from './quickpicks/remotesQuickPick'; export * from './quickpicks/repositoriesQuickPick'; export * from './quickpicks/repoStatusQuickPick'; -export * from './quickpicks/stashListQuickPick'; diff --git a/src/quickpicks/stashListQuickPick.ts b/src/quickpicks/stashListQuickPick.ts deleted file mode 100644 index 84963be..0000000 --- a/src/quickpicks/stashListQuickPick.ts +++ /dev/null @@ -1,80 +0,0 @@ -'use strict'; -import { CancellationTokenSource, window } from 'vscode'; -import { Commands, StashSaveCommandArgs } from '../commands'; -import { GlyphChars } from '../constants'; -import { Container } from '../container'; -import { GitStash, GitStashCommit } from '../git/gitService'; -import { KeyNoopCommand } from '../keyboard'; -import { Iterables } from '../system'; -import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './commonQuickPicks'; -import { CommitQuickPickItem } from './gitQuickPicks'; - -export class StashListQuickPick { - static showProgress(mode: 'list' | 'apply') { - const message = - mode === 'apply' - ? `Apply stash to your working tree${GlyphChars.Ellipsis}` - : `stashes ${GlyphChars.Dash} search by message, filename, or commit id`; - return showQuickPickProgress(message, { - left: KeyNoopCommand, - ',': KeyNoopCommand, - '.': KeyNoopCommand - }); - } - - static async show( - stash: GitStash, - mode: 'list' | 'apply', - progressCancellation: CancellationTokenSource, - goBackCommand?: CommandQuickPickItem, - currentCommand?: CommandQuickPickItem - ): Promise | CommandQuickPickItem | undefined> { - const items = ((stash && - Array.from(Iterables.map(stash.commits.values(), c => CommitQuickPickItem.create(c)))) || - []) as (CommitQuickPickItem | CommandQuickPickItem)[]; - - if (mode === 'list') { - const commandArgs: StashSaveCommandArgs = { - goBackCommand: currentCommand - }; - items.splice( - 0, - 0, - new CommandQuickPickItem( - { - label: '$(plus) Stash Changes', - description: 'stashes all changes' - }, - Commands.StashSave, - [commandArgs] - ) - ); - } - - if (goBackCommand) { - items.splice(0, 0, goBackCommand); - } - - if (progressCancellation.token.isCancellationRequested) return undefined; - - const scope = await Container.keyboard.beginScope({ left: goBackCommand }); - - progressCancellation.cancel(); - - const pick = await window.showQuickPick(items, { - matchOnDescription: true, - placeHolder: - mode === 'apply' - ? `Apply stash to your working tree${GlyphChars.Ellipsis}` - : `stashes ${GlyphChars.Dash} search by message, filename, or commit id`, - ignoreFocusOut: getQuickPickIgnoreFocusOut() - // onDidSelectItem: (item: QuickPickItem) => { - // scope.setKeyCommand('right', item); - // } - }); - - await scope.dispose(); - - return pick; - } -}