From a2a3f1a81eae8fa4adf393f7f3cf21796c309314 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 11 Mar 2017 04:14:47 -0500 Subject: [PATCH] Adds commit navigation in quick pick lists via alt+, alt+. Reworks keyboard context --- package.json | 32 ++++++++++---------------- src/commands.ts | 2 +- src/commands/keyboard.ts | 37 ++++++++++++++++++++++++------ src/commands/showQuickCommitDetails.ts | 31 ++++++++++++++++--------- src/commands/showQuickCommitFileDetails.ts | 36 +++++++++++++++++------------ src/commands/showQuickFileHistory.ts | 17 ++++++++------ src/commands/showQuickRepoHistory.ts | 17 ++++++++------ src/extension.ts | 2 +- src/quickPicks/commitDetails.ts | 33 ++++++++++++++++++++++---- src/quickPicks/commitFileDetails.ts | 33 ++++++++++++++++++++++---- src/quickPicks/fileHistory.ts | 2 +- src/quickPicks/quickPicks.ts | 18 +++++++++++++++ src/quickPicks/repoHistory.ts | 2 +- 13 files changed, 181 insertions(+), 81 deletions(-) diff --git a/package.json b/package.json index 9cad3cf..cc4986d 100644 --- a/package.json +++ b/package.json @@ -342,16 +342,6 @@ }, "commands": [ { - "command": "gitlens.key.left", - "title": "Left KeyPress", - "category": "GitLens:KeyPress" - }, - { - "command": "gitlens.key.right", - "title": "Right KeyPress", - "category": "GitLens:KeyPress" - }, - { "command": "gitlens.diffDirectory", "title": "Directory Compare", "category": "GitLens" @@ -459,14 +449,6 @@ "menus": { "commandPalette": [ { - "command": "gitlens.key.left", - "when": "false" - }, - { - "command": "gitlens.key.right", - "when": "false" - }, - { "command": "gitlens.diffDirectory", "when": "gitlens:enabled" }, @@ -661,12 +643,22 @@ { "command": "gitlens.key.left", "key": "alt+left", - "when": "gitlens:key" + "when": "gitlens:key:left" }, { "command": "gitlens.key.right", "key": "alt+right", - "when": "gitlens:key" + "when": "gitlens:key:right" + }, + { + "command": "gitlens.key.,", + "key": "alt+,", + "when": "gitlens:key:," + }, + { + "command": "gitlens.key..", + "key": "alt+.", + "when": "gitlens:key:." }, { "command": "gitlens.toggleBlame", diff --git a/src/commands.ts b/src/commands.ts index da6dd55..8ce8753 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -35,6 +35,6 @@ export const CommandContext = { }; -export function setCommandContext(key: CommandContext, value: any) { +export function setCommandContext(key: CommandContext | string, value: any) { return commands.executeCommand(BuiltInCommands.SetContext, key, value); } \ No newline at end of file diff --git a/src/commands/keyboard.ts b/src/commands/keyboard.ts index f30f02b..6f92a93 100644 --- a/src/commands/keyboard.ts +++ b/src/commands/keyboard.ts @@ -4,13 +4,21 @@ import { CommandContext, setCommandContext } from '../commands'; import { CommandQuickPickItem, OpenFileCommandQuickPickItem } from '../quickPicks/quickPicks'; import { Logger } from '../logger'; -export declare type Keys = 'left' | 'right'; +export declare type Keys = 'left' | 'right' | ',' | '.'; export const keys: Keys[] = [ 'left', - 'right' + 'right', + ',', + '.' ]; let scopeCount = 0; +let counters = { + left: 0, + right: 0, + ',': 0, + '.': 0 +}; let _instance: Keyboard; @@ -41,7 +49,10 @@ export class Keyboard extends Disposable { } async execute(key: Keys): Promise<{}> { - const command = this.context.globalState.get(`gitlens:key:${key}`) as CommandQuickPickItem; + let command = this.context.globalState.get(`gitlens:key:${key}`) as CommandQuickPickItem | (() => Promise); + if (typeof command === 'function') { + command = await command(); + } if (!command || !(command instanceof CommandQuickPickItem)) return undefined; Logger.log('Keyboard.execute', key); @@ -54,11 +65,13 @@ export class Keyboard extends Disposable { return await command.execute(); } - async enterScope(...keyCommands: [Keys, QuickPickItem][]) { + async enterScope(...keyCommands: [Keys, QuickPickItem | (() => Promise)][]) { Logger.log('Keyboard.enterScope', scopeCount); - await setCommandContext(CommandContext.Key, ++scopeCount); + scopeCount++; + // await setCommandContext(CommandContext.Key, ++scopeCount); if (keyCommands && Array.isArray(keyCommands) && keyCommands.length) { for (const [key, command] of keyCommands) { + await setCommandContext(`${CommandContext.Key}:${key}`, ++counters[key]); await this.setKeyCommand(key as Keys, command); } } @@ -66,9 +79,15 @@ export class Keyboard extends Disposable { async exitScope(clear: boolean = true) { Logger.log('Keyboard.exitScope', scopeCount); - await setCommandContext(CommandContext.Key, --scopeCount); + if (scopeCount) { + scopeCount--; + // await setCommandContext(CommandContext.Key, --scopeCount); + } if (clear && !scopeCount) { for (const key of keys) { + if (counters[key]) { + await setCommandContext(`${CommandContext.Key}:${key}`, --counters[key]); + } await this.clearKeyCommand(key); } } @@ -76,11 +95,15 @@ export class Keyboard extends Disposable { async clearKeyCommand(key: Keys) { Logger.log('Keyboard.clearKeyCommand', key); + if (counters[key]) { + await setCommandContext(`${CommandContext.Key}:${key}`, --counters[key]); + } await this.context.globalState.update(`gitlens:key:${key}`, undefined); } - async setKeyCommand(key: Keys, command: QuickPickItem) { + async setKeyCommand(key: Keys, command: QuickPickItem | (() => Promise)) { Logger.log('Keyboard.setKeyCommand', key); + await setCommandContext(`${CommandContext.Key}:${key}`, ++counters[key]); await this.context.globalState.update(`gitlens:key:${key}`, command); } } \ No newline at end of file diff --git a/src/commands/showQuickCommitDetails.ts b/src/commands/showQuickCommitDetails.ts index bfacb59..87d3b26 100644 --- a/src/commands/showQuickCommitDetails.ts +++ b/src/commands/showQuickCommitDetails.ts @@ -1,18 +1,17 @@ 'use strict'; -import { Iterables } from '../system'; import { commands, TextEditor, Uri, window } from 'vscode'; import { ActiveEditorCommand, Commands } from './commands'; -import { GitCommit, GitLogCommit, GitProvider, GitUri } from '../gitProvider'; +import { GitCommit, GitLogCommit, GitProvider, GitUri, IGitLog } from '../gitProvider'; import { Logger } from '../logger'; import { CommandQuickPickItem, CommitDetailsQuickPick, CommitWithFileStatusQuickPickItem } from '../quickPicks'; export class ShowQuickCommitDetailsCommand extends ActiveEditorCommand { - constructor(private git: GitProvider) { + constructor(private git: GitProvider, private repoPath: string) { super(Commands.ShowQuickCommitDetails); } - async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem) { + async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem, repoLog?: IGitLog) { if (!(uri instanceof Uri)) { if (!editor || !editor.document) return undefined; uri = editor.document.uri; @@ -45,21 +44,31 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCommand { try { if (!commit || !(commit instanceof GitLogCommit) || commit.type !== 'repo') { - let log = await this.git.getLogForRepo(repoPath, sha, 2); - if (!log) return window.showWarningMessage(`Unable to show commit details`); - - commit = Iterables.first(log.commits.values()); + if (repoLog) { + commit = repoLog.commits.get(sha); + // If we can't find the commit, kill the repoLog + if (!commit) { + repoLog = undefined; + } + } + + if (!repoLog) { + const log = await this.git.getLogForRepo(repoPath || this.repoPath, sha, 2); + if (!log) return window.showWarningMessage(`Unable to show commit details`); + + commit = log.commits.get(sha); + } } if (!goBackCommand) { - // Create a command to get back to the commit details + // Create a command to get back to the repository history goBackCommand = new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to repository history` }, Commands.ShowQuickRepoHistory, [new GitUri(commit.uri, commit)]); } - const pick = await CommitDetailsQuickPick.show(commit as GitLogCommit, uri, goBackCommand); + const pick = await CommitDetailsQuickPick.show(this.git, commit as GitLogCommit, uri, goBackCommand, repoLog); if (!pick) return undefined; if (!(pick instanceof CommitWithFileStatusQuickPickItem)) { @@ -71,7 +80,7 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCommand { new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(git-commit) ${pick.shortSha}` - }, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), sha, commit, goBackCommand])); + }, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), sha, commit, goBackCommand, repoLog])); } catch (ex) { Logger.error('[GitLens.ShowQuickCommitDetailsCommand]', ex); diff --git a/src/commands/showQuickCommitFileDetails.ts b/src/commands/showQuickCommitFileDetails.ts index a1e8212..b7a186f 100644 --- a/src/commands/showQuickCommitFileDetails.ts +++ b/src/commands/showQuickCommitFileDetails.ts @@ -1,8 +1,7 @@ 'use strict'; -import { Iterables } from '../system'; import { TextEditor, Uri, window } from 'vscode'; import { ActiveEditorCommand, Commands } from './commands'; -import { GitCommit, GitLogCommit, GitProvider, GitUri } from '../gitProvider'; +import { GitCommit, GitLogCommit, GitProvider, GitUri, IGitLog } from '../gitProvider'; import { Logger } from '../logger'; import { CommandQuickPickItem, CommitFileDetailsQuickPick } from '../quickPicks'; import * as path from 'path'; @@ -13,19 +12,17 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCommand { super(Commands.ShowQuickCommitFileDetails); } - async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem, options: { showFileHistory?: boolean } = { showFileHistory: true }) { + async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem, options: { showFileHistory?: boolean } = { showFileHistory: true }, fileLog?: IGitLog) { if (!(uri instanceof Uri)) { if (!editor || !editor.document) return undefined; uri = editor.document.uri; } - const gitUri = await GitUri.fromUri(uri, this.git); - - let repoPath = gitUri.repoPath; - if (!sha) { if (!editor) return undefined; + const gitUri = await GitUri.fromUri(uri, this.git); + const blameline = editor.selection.active.line - gitUri.offset; if (blameline < 0) return undefined; @@ -34,7 +31,6 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCommand { if (!blame) return window.showWarningMessage(`Unable to show commit file details. File is probably not under source control`); sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha; - repoPath = blame.commit.repoPath; commit = blame.commit; } @@ -45,11 +41,21 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCommand { } try { - if (!commit || ((commit instanceof GitLogCommit) && commit.type !== 'file')) { - let log = await this.git.getLogForFile(uri.fsPath, sha, undefined, undefined, 2); - if (!log) return window.showWarningMessage(`Unable to show commit file details`); - - commit = Iterables.find(log.commits.values(), c => c.sha === sha); + if (!commit || !(commit instanceof GitLogCommit) || commit.type !== 'file') { + if (fileLog) { + commit = fileLog.commits.get(sha); + // If we can't find the commit, kill the fileLog + if (!commit) { + fileLog = undefined; + } + } + + if (!fileLog) { + const log = await this.git.getLogForFile(uri.fsPath, sha, undefined, undefined, 2); + if (!log) return window.showWarningMessage(`Unable to show commit file details`); + + commit = log.commits.get(sha); + } } // Attempt to the most recent commit -- so that we can find the real working filename if there was a rename @@ -67,13 +73,13 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCommand { }, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), sha, commit]); } - const pick = await CommitFileDetailsQuickPick.show(this.git, commit, workingFileName, uri, goBackCommand, + const pick = await CommitFileDetailsQuickPick.show(this.git, commit as GitLogCommit, workingFileName, uri, goBackCommand, // Create a command to get back to where we are right now new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(file-text) ${path.basename(commit.fileName)} in \u00a0$(git-commit) ${shortSha}` }, Commands.ShowQuickCommitFileDetails, [new GitUri(commit.uri, commit), sha, commit, goBackCommand, options]), - { showFileHistory: options.showFileHistory }); + { showFileHistory: options.showFileHistory }, fileLog); if (!pick) return undefined; diff --git a/src/commands/showQuickFileHistory.ts b/src/commands/showQuickFileHistory.ts index fca4cfc..79a7229 100644 --- a/src/commands/showQuickFileHistory.ts +++ b/src/commands/showQuickFileHistory.ts @@ -1,7 +1,7 @@ 'use strict'; import { commands, TextEditor, Uri, window } from 'vscode'; import { ActiveEditorCommand, Commands } from './commands'; -import { GitProvider, GitUri } from '../gitProvider'; +import { GitProvider, GitUri, IGitLog } from '../gitProvider'; import { Logger } from '../logger'; import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks'; import * as path from 'path'; @@ -12,7 +12,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCommand { super(Commands.ShowQuickFileHistory); } - async execute(editor: TextEditor, uri?: Uri, maxCount?: number, goBackCommand?: CommandQuickPickItem) { + async execute(editor: TextEditor, uri?: Uri, maxCount?: number, goBackCommand?: CommandQuickPickItem, log?: IGitLog) { if (!(uri instanceof Uri)) { uri = editor && editor.document && editor.document.uri; } @@ -28,10 +28,12 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCommand { } try { - const log = await this.git.getLogForFile(gitUri.fsPath, gitUri.sha, gitUri.repoPath, undefined, maxCount); - if (!log) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`); + if (!log) { + log = await this.git.getLogForFile(gitUri.fsPath, gitUri.sha, gitUri.repoPath, undefined, maxCount); + if (!log) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`); + } - let pick = await FileHistoryQuickPick.show(log, uri, gitUri.sha, maxCount, this.git.config.advanced.maxQuickHistory, goBackCommand); + const pick = await FileHistoryQuickPick.show(log, uri, gitUri.sha, maxCount, this.git.config.advanced.maxQuickHistory, goBackCommand); if (!pick) return undefined; if (pick instanceof CommandQuickPickItem) { @@ -42,8 +44,9 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCommand { new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(pick.commit.fileName)}` - }, Commands.ShowQuickFileHistory, [uri, maxCount, goBackCommand]), - { showFileHistory: false }); + }, Commands.ShowQuickFileHistory, [uri, maxCount, goBackCommand, log]), + { showFileHistory: false }, + log); } catch (ex) { Logger.error('[GitLens.ShowQuickFileHistoryCommand]', 'getLogLocations', ex); diff --git a/src/commands/showQuickRepoHistory.ts b/src/commands/showQuickRepoHistory.ts index 3baf038..fcb3960 100644 --- a/src/commands/showQuickRepoHistory.ts +++ b/src/commands/showQuickRepoHistory.ts @@ -1,7 +1,7 @@ 'use strict'; import { commands, TextEditor, Uri, window } from 'vscode'; import { ActiveEditorCommand, Commands } from './commands'; -import { GitProvider, GitUri } from '../gitProvider'; +import { GitProvider, GitUri, IGitLog } from '../gitProvider'; import { Logger } from '../logger'; import { CommandQuickPickItem, RepoHistoryQuickPick } from '../quickPicks'; @@ -11,7 +11,7 @@ export class ShowQuickRepoHistoryCommand extends ActiveEditorCommand { super(Commands.ShowQuickRepoHistory); } - async execute(editor: TextEditor, uri?: Uri, maxCount?: number, goBackCommand?: CommandQuickPickItem) { + async execute(editor: TextEditor, uri?: Uri, maxCount?: number, goBackCommand?: CommandQuickPickItem, log?: IGitLog) { if (!(uri instanceof Uri)) { uri = editor && editor.document && editor.document.uri; } @@ -21,11 +21,13 @@ export class ShowQuickRepoHistoryCommand extends ActiveEditorCommand { } try { - const repoPath = await this.git.getRepoPathFromUri(uri, this.repoPath); - if (!repoPath) return window.showWarningMessage(`Unable to show repository history`); + if (!log) { + const repoPath = await this.git.getRepoPathFromUri(uri, this.repoPath); + if (!repoPath) return window.showWarningMessage(`Unable to show repository history`); - const log = await this.git.getLogForRepo(repoPath, undefined, maxCount); - if (!log) return window.showWarningMessage(`Unable to show repository history`); + log = await this.git.getLogForRepo(repoPath, undefined, maxCount); + if (!log) return window.showWarningMessage(`Unable to show repository history`); + } const pick = await RepoHistoryQuickPick.show(log, uri, maxCount, this.git.config.advanced.maxQuickHistory, goBackCommand); if (!pick) return undefined; @@ -38,7 +40,8 @@ export class ShowQuickRepoHistoryCommand extends ActiveEditorCommand { new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to repository history` - }, Commands.ShowQuickRepoHistory, [uri, maxCount, goBackCommand])); + }, Commands.ShowQuickRepoHistory, [uri, maxCount, goBackCommand, log]), + log); } catch (ex) { Logger.error('[GitLens.ShowQuickRepoHistoryCommand]', ex); diff --git a/src/extension.ts b/src/extension.ts index 5ba3eb8..48c4301 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -102,7 +102,7 @@ export async function activate(context: ExtensionContext) { context.subscriptions.push(new ToggleBlameCommand(annotationController)); context.subscriptions.push(new ShowBlameHistoryCommand(git)); context.subscriptions.push(new ShowFileHistoryCommand(git)); - context.subscriptions.push(new ShowQuickCommitDetailsCommand(git)); + context.subscriptions.push(new ShowQuickCommitDetailsCommand(git, repoPath)); context.subscriptions.push(new ShowQuickCommitFileDetailsCommand(git)); context.subscriptions.push(new ShowQuickFileHistoryCommand(git)); context.subscriptions.push(new ShowQuickRepoHistoryCommand(git, repoPath)); diff --git a/src/quickPicks/commitDetails.ts b/src/quickPicks/commitDetails.ts index 7a04da2..570ddb4 100644 --- a/src/quickPicks/commitDetails.ts +++ b/src/quickPicks/commitDetails.ts @@ -1,9 +1,9 @@ 'use strict'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { Commands, Keyboard } from '../commands'; -import { GitLogCommit, GitProvider } from '../gitProvider'; +import { GitLogCommit, GitProvider, IGitLog } from '../gitProvider'; import { CommitWithFileStatusQuickPickItem } from './gitQuickPicks'; -import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFilesCommandQuickPickItem } from './quickPicks'; +import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, KeyNoopCommandQuickPickItem, OpenFilesCommandQuickPickItem } from './quickPicks'; import * as moment from 'moment'; import * as path from 'path'; @@ -35,7 +35,7 @@ export class OpenCommitWorkingTreeFilesCommandQuickPickItem extends OpenFilesCom export class CommitDetailsQuickPick { - static async show(commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem): Promise { + static async show(git: GitProvider, commit: GitLogCommit, uri: Uri, goBackCommand?: CommandQuickPickItem, repoLog?: IGitLog): Promise { const items: (CommitWithFileStatusQuickPickItem | CommandQuickPickItem)[] = commit.fileStatuses.map(fs => new CommitWithFileStatusQuickPickItem(commit, fs.fileName, fs.status)); let index = 0; @@ -63,7 +63,7 @@ export class CommitDetailsQuickPick { items.splice(index++, 0, new CommandQuickPickItem({ label: `Changed Files`, description: null - }, Commands.ShowQuickCommitDetails, [uri, commit.sha, commit, goBackCommand])); + }, Commands.ShowQuickCommitDetails, [uri, commit.sha, commit, goBackCommand, repoLog])); items.push(new OpenCommitFilesCommandQuickPickItem(commit)); items.push(new OpenCommitWorkingTreeFilesCommandQuickPickItem(commit)); @@ -72,7 +72,30 @@ export class CommitDetailsQuickPick { items.splice(0, 0, goBackCommand); } - await Keyboard.instance.enterScope(['left', goBackCommand]); + const previousCommand = commit.previousSha + ? new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [commit.previousUri, commit.previousSha, undefined, goBackCommand, repoLog]) + : new KeyNoopCommandQuickPickItem(); + + let nextCommand: CommandQuickPickItem | (() => Promise); + if (repoLog) { + nextCommand = commit.nextSha + ? new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [commit.nextUri, commit.nextSha, undefined, goBackCommand, repoLog]) + : new KeyNoopCommandQuickPickItem(); + } + else { + nextCommand = async () => { + const log = await git.getLogForRepo(commit.repoPath, undefined, git.config.advanced.maxQuickHistory); + const c = log && log.commits.get(commit.sha); + if (!c) return new KeyNoopCommandQuickPickItem(); + return new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [c.nextUri, c.nextSha, undefined, goBackCommand, log]); + }; + } + + await Keyboard.instance.enterScope( + ['left', goBackCommand], + [',', previousCommand], + ['.', nextCommand] + ); const pick = await window.showQuickPick(items, { matchOnDescription: true, diff --git a/src/quickPicks/commitFileDetails.ts b/src/quickPicks/commitFileDetails.ts index 583dea2..a4138cb 100644 --- a/src/quickPicks/commitFileDetails.ts +++ b/src/quickPicks/commitFileDetails.ts @@ -2,8 +2,8 @@ import { Iterables } from '../system'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { Commands, Keyboard } from '../commands'; -import { GitCommit, GitLogCommit, GitProvider, GitUri } from '../gitProvider'; -import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem } from './quickPicks'; +import { GitCommit, GitLogCommit, GitProvider, GitUri, IGitLog } from '../gitProvider'; +import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, KeyNoopCommandQuickPickItem, OpenFileCommandQuickPickItem } from './quickPicks'; import * as moment from 'moment'; import * as path from 'path'; @@ -31,7 +31,7 @@ export class OpenCommitWorkingTreeFileCommandQuickPickItem extends OpenFileComma export class CommitFileDetailsQuickPick { - static async show(git: GitProvider, commit: GitCommit | GitLogCommit, workingFileName: string, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, options: { showFileHistory?: boolean } = {}): Promise { + static async show(git: GitProvider, commit: GitLogCommit, workingFileName: string, uri: Uri, goBackCommand?: CommandQuickPickItem, currentCommand?: CommandQuickPickItem, options: { showFileHistory?: boolean } = {}, fileLog?: IGitLog): Promise { const items: CommandQuickPickItem[] = []; const workingName = (workingFileName && path.basename(workingFileName)) || path.basename(commit.fileName); @@ -81,7 +81,7 @@ export class CommitFileDetailsQuickPick { items.push(new CommandQuickPickItem({ label: `$(history) Show File History`, description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(commit.fileName)}` - }, Commands.ShowQuickFileHistory, [commit.uri, undefined, currentCommand])); + }, Commands.ShowQuickFileHistory, [commit.uri, undefined, currentCommand, fileLog])); } items.push(new CommandQuickPickItem({ @@ -93,7 +93,30 @@ export class CommitFileDetailsQuickPick { items.splice(0, 0, goBackCommand); } - await Keyboard.instance.enterScope(['left', goBackCommand]); + const previousCommand = commit.previousSha + ? new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [commit.previousUri, commit.previousSha, undefined, goBackCommand, options, fileLog]) + : new KeyNoopCommandQuickPickItem(); + + let nextCommand: CommandQuickPickItem | (() => Promise); + if (fileLog) { + nextCommand = commit.nextSha + ? new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [commit.nextUri, commit.nextSha, undefined, goBackCommand, options, fileLog]) + : new KeyNoopCommandQuickPickItem(); + } + else { + nextCommand = async () => { + const log = await git.getLogForFile(uri.fsPath, undefined, commit.repoPath, undefined, git.config.advanced.maxQuickHistory); + const c = log && log.commits.get(commit.sha); + if (!c) return new KeyNoopCommandQuickPickItem(); + return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [c.nextUri, c.nextSha, undefined, goBackCommand, options, log]); + }; + } + + await Keyboard.instance.enterScope( + ['left', goBackCommand], + [',', previousCommand], + ['.', nextCommand] + ); const pick = await window.showQuickPick(items, { matchOnDescription: true, diff --git a/src/quickPicks/fileHistory.ts b/src/quickPicks/fileHistory.ts index 6a8f798..7e5fd62 100644 --- a/src/quickPicks/fileHistory.ts +++ b/src/quickPicks/fileHistory.ts @@ -33,7 +33,7 @@ export class FileHistoryQuickPick { new CommandQuickPickItem({ label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}` - }, Commands.ShowQuickFileHistory, [uri, maxCount]) + }, Commands.ShowQuickFileHistory, [uri, maxCount, undefined, log]) ])); } diff --git a/src/quickPicks/quickPicks.ts b/src/quickPicks/quickPicks.ts index 6fc291e..1dbf456 100644 --- a/src/quickPicks/quickPicks.ts +++ b/src/quickPicks/quickPicks.ts @@ -22,6 +22,24 @@ export class CommandQuickPickItem implements QuickPickItem { } } +export class KeyCommandQuickPickItem extends CommandQuickPickItem { + + constructor(protected command: Commands, protected args?: any[]) { + super({ label: undefined, description: undefined }, command, args); + } +} + +export class KeyNoopCommandQuickPickItem extends CommandQuickPickItem { + + constructor() { + super({ label: undefined, description: undefined }, undefined, undefined); + } + + execute(): Thenable<{}> { + return Promise.resolve(undefined); + } +} + export class OpenFileCommandQuickPickItem extends CommandQuickPickItem { constructor(public uri: Uri, item: QuickPickItem) { diff --git a/src/quickPicks/repoHistory.ts b/src/quickPicks/repoHistory.ts index 62d2a48..f518d3b 100644 --- a/src/quickPicks/repoHistory.ts +++ b/src/quickPicks/repoHistory.ts @@ -9,7 +9,7 @@ import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './quickPicks'; export class RepoHistoryQuickPick { static async show(log: IGitLog, uri: Uri, maxCount: number, defaultMaxCount: number, goBackCommand?: CommandQuickPickItem): Promise { - const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c, ` \u2014 ${c.fileName}`))) as (CommitQuickPickItem | CommandQuickPickItem)[]; + const items = Array.from(Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c, ` \u2014 ${c.fileNames}`))) as (CommitQuickPickItem | CommandQuickPickItem)[]; if (maxCount !== 0 && items.length >= defaultMaxCount) { items.splice(0, 0, new CommandQuickPickItem({