From 615485cd215cfdfc02bafb0e5ab5e66d7a8525f1 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 25 Nov 2016 14:12:39 -0500 Subject: [PATCH] Adds compare options to repository history Adds compare options to file history Fixes issue with repository history compare with commits with multiple files --- src/commands/quickPickItems.ts | 34 ++++++++++++ src/commands/showQuickFileHistory.ts | 51 ++++++++++++------ src/commands/showQuickRepoHistory.ts | 72 ++++++++++++++------------ src/git/enrichers/logParserEnricher.ts | 3 +- src/gitProvider.ts | 14 ++++- 5 files changed, 121 insertions(+), 53 deletions(-) create mode 100644 src/commands/quickPickItems.ts diff --git a/src/commands/quickPickItems.ts b/src/commands/quickPickItems.ts new file mode 100644 index 0000000..c93eff9 --- /dev/null +++ b/src/commands/quickPickItems.ts @@ -0,0 +1,34 @@ +'use strict'; +import { QuickPickItem, Uri } from 'vscode'; +import { Commands } from '../constants'; +import { GitCommit, GitUri } from '../gitProvider'; +import * as moment from 'moment'; +import * as path from 'path'; + +export class CommitQuickPickItem implements QuickPickItem { + label: string; + description: string; + detail: string; + + constructor(public commit: GitCommit, descriptionSuffix: string = '') { + this.label = `${commit.author}, ${moment(commit.date).fromNow()}`; + this.description = `$(git-commit) ${commit.sha}${descriptionSuffix}`; + this.detail = commit.message; + } +} + +export interface CompareQuickPickItem extends QuickPickItem { + command: Commands; +} + +export class FileQuickPickItem implements QuickPickItem { + label: string; + description: string; + detail: string; + uri: GitUri; + + constructor(commit: GitCommit, public fileName: string) { + this.label = fileName; + this.uri = GitUri.fromUri(Uri.file(path.resolve(commit.repoPath, fileName))); + } +} diff --git a/src/commands/showQuickFileHistory.ts b/src/commands/showQuickFileHistory.ts index bdc665a..300aae7 100644 --- a/src/commands/showQuickFileHistory.ts +++ b/src/commands/showQuickFileHistory.ts @@ -1,24 +1,13 @@ 'use strict'; import { Iterables } from '../system'; -import { commands, QuickPickItem, QuickPickOptions, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; +import { commands, QuickPickOptions, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { EditorCommand } from './commands'; import { Commands } from '../constants'; -import GitProvider, { GitCommit, GitUri } from '../gitProvider'; +import GitProvider, { GitUri } from '../gitProvider'; import { Logger } from '../logger'; +import { CommitQuickPickItem, CompareQuickPickItem } from './quickPickItems'; import * as moment from 'moment'; -class CommitQuickPickItem implements QuickPickItem { - label: string; - description: string; - detail: string; - - constructor(public commit: GitCommit) { - this.label = `${commit.author}, ${moment(commit.date).fromNow()}`; - this.description = `\u2022 ${commit.sha}`; - this.detail = commit.message; - } -} - export default class ShowQuickFileHistoryCommand extends EditorCommand { constructor(private git: GitProvider) { super(Commands.ShowQuickFileHistory); @@ -39,11 +28,41 @@ export default class ShowQuickFileHistoryCommand extends EditorCommand { const items = Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c)); const commitPick = await window.showQuickPick(Array.from(items), { matchOnDescription: true, - matchOnDetail: true + matchOnDetail: true, + placeHolder: Iterables.first(log.commits.values()).fileName }); if (commitPick) { - return commands.executeCommand(Commands.DiffWithWorking, commitPick.commit.uri, commitPick.commit); + const commit = commitPick.commit; + + let command: Commands | undefined = Commands.DiffWithWorking; + if (commit.previousSha) { + const items: CompareQuickPickItem[] = [ + { + label: `Compare with Working Tree`, + description: `\u2022 ${commit.sha} $(git-compare) ${commit.fileName}`, + detail: null, + command: Commands.DiffWithWorking + }, + { + label: `Compare with Previous Commit`, + description: `\u2022 ${commit.previousSha} $(git-compare) ${commit.sha}`, + detail: null, + command: Commands.DiffWithPrevious + } + ]; + + const comparePick = await window.showQuickPick(items, { + matchOnDescription: true, + placeHolder: `${commit.fileName} \u2022 ${commit.sha} \u2022 ${commit.author}, ${moment(commit.date).fromNow()}` + }); + + command = comparePick ? comparePick.command : undefined; + } + + if (command) { + return commands.executeCommand(command, commit.uri, commit); + } } } catch (ex) { diff --git a/src/commands/showQuickRepoHistory.ts b/src/commands/showQuickRepoHistory.ts index 2f885ba..469df4a 100644 --- a/src/commands/showQuickRepoHistory.ts +++ b/src/commands/showQuickRepoHistory.ts @@ -1,37 +1,12 @@ 'use strict'; import { Iterables } from '../system'; -import { commands, QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; +import { commands, QuickPickOptions, Uri, window } from 'vscode'; import { Command } from './commands'; import { Commands } from '../constants'; -import GitProvider, { GitCommit, GitUri } from '../gitProvider'; +import GitProvider, { GitUri } from '../gitProvider'; import { Logger } from '../logger'; +import { CommitQuickPickItem, CompareQuickPickItem, FileQuickPickItem } from './quickPickItems'; import * as moment from 'moment'; -import * as path from 'path'; - -class CommitQuickPickItem implements QuickPickItem { - label: string; - description: string; - detail: string; - - constructor(public commit: GitCommit) { - this.label = `${commit.author}, ${moment(commit.date).fromNow()}`; - this.description = `\u2022 ${commit.sha} \u2014 ${commit.fileName}`; - this.detail = commit.message; - } -} - -class FileQuickPickItem implements QuickPickItem { - label: string; - description: string; - detail: string; - uri: GitUri; - - constructor(commit: GitCommit, public fileName: string) { - this.label = fileName; - this.uri = GitUri.fromUri(Uri.file(path.resolve(commit.repoPath, fileName))); - } -} - export default class ShowQuickRepoHistoryCommand extends Command { constructor(private git: GitProvider, public repoPath: string) { super(Commands.ShowQuickRepoHistory); @@ -40,7 +15,7 @@ export default class ShowQuickRepoHistoryCommand extends Command { async execute(uri?: Uri) { if (!(uri instanceof Uri)) { const document = window.activeTextEditor && window.activeTextEditor.document; - if (document) { + if (document) { uri = document.uri; } } @@ -65,7 +40,7 @@ export default class ShowQuickRepoHistoryCommand extends Command { const log = await this.git.getLogForRepo(repoPath); if (!log) return window.showWarningMessage(`Unable to show repository history`); - const items = Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c)); + const items = Iterables.map(log.commits.values(), c => new CommitQuickPickItem(c, ` \u2014 ${c.fileName}`)); const commitPick = await window.showQuickPick(Array.from(items), { matchOnDescription: true, matchOnDetail: true @@ -76,12 +51,43 @@ export default class ShowQuickRepoHistoryCommand extends Command { const filePick = await window.showQuickPick(items, { matchOnDescription: true, matchOnDetail: true, - placeHolder: `${commitPick.commit.author}, ${moment(commitPick.commit.date).fromNow()} \u2022 ${commitPick.commit.sha}` + placeHolder: `${commitPick.commit.sha} \u2022 ${commitPick.commit.author}, ${moment(commitPick.commit.date).fromNow()}` }); if (filePick) { - const commit = new GitCommit(commitPick.commit.repoPath, commitPick.commit.sha, filePick.fileName, commitPick.commit.author, commitPick.commit.date, commitPick.commit.message, undefined, undefined, commitPick.commit.previousSha); - return commands.executeCommand(Commands.DiffWithWorking, filePick.uri, commit); + const log = await this.git.getLogForFile(filePick.uri.fsPath); + if (!log) return window.showWarningMessage(`Unable to open diff`); + + const commit = Iterables.find(log.commits.values(), c => c.sha === commitPick.commit.sha); + + let command: Commands | undefined = Commands.DiffWithWorking; + if (commit.previousSha) { + const items: CompareQuickPickItem[] = [ + { + label: `Compare with Working Tree`, + description: `\u2022 ${commit.sha} $(git-compare) ${commit.fileName}`, + detail: null, + command: Commands.DiffWithWorking + }, + { + label: `Compare with Previous Commit`, + description: `\u2022 ${commit.previousSha} $(git-compare) ${commit.sha}`, + detail: null, + command: Commands.DiffWithPrevious + } + ]; + + const comparePick = await window.showQuickPick(items, { + matchOnDescription: true, + placeHolder: `${commit.fileName} \u2022 ${commit.sha} \u2022 ${commit.author}, ${moment(commit.date).fromNow()}` + }); + + command = comparePick ? comparePick.command : undefined; + } + + if (command) { + return commands.executeCommand(command, commit.uri, commit); + } } } diff --git a/src/git/enrichers/logParserEnricher.ts b/src/git/enrichers/logParserEnricher.ts index c93b582..d4368e9 100644 --- a/src/git/enrichers/logParserEnricher.ts +++ b/src/git/enrichers/logParserEnricher.ts @@ -108,8 +108,7 @@ export class GitLogParserEnricher implements IGitEnricher { return entries; } - enrich(data: string, fileNameOrRepoPath: string): IGitLog { - const isRepoPath = !path.extname(fileNameOrRepoPath); + enrich(data: string, fileNameOrRepoPath: string, isRepoPath: boolean = false): IGitLog { const entries = this._parseEntries(data, isRepoPath); if (!entries) return undefined; diff --git a/src/gitProvider.ts b/src/gitProvider.ts index 3eebee9..1e11670 100644 --- a/src/gitProvider.ts +++ b/src/gitProvider.ts @@ -351,7 +351,7 @@ export default class GitProvider extends Disposable { Logger.log(`getLogForRepo('${repoPath}')`); try { const data = await Git.logRepo(repoPath); - return new GitLogParserEnricher().enrich(data, repoPath); + return new GitLogParserEnricher().enrich(data, repoPath, true); } catch (ex) { return undefined; @@ -529,7 +529,7 @@ export class GitUri extends Uri { repoPath?: string | undefined; sha?: string | undefined; - constructor(uri?: Uri) { + constructor(uri?: Uri, commit?: GitCommit) { super(); if (!uri) return; @@ -549,12 +549,22 @@ export class GitUri extends Uri { this.repoPath = data.repoPath; this.sha = data.sha; } + else if (commit) { + base._fsPath = commit.originalFileName || commit.fileName; + + this.repoPath = commit.repoPath; + this.sha = commit.sha; + } } fileUri() { return Uri.file(this.fsPath); } + static fromCommit(uri: Uri, commit: GitCommit) { + return new GitUri(uri, commit); + } + static fromUri(uri: Uri) { return new GitUri(uri); }