Refactors commands to use typed args objects

This commit is contained in:
Eric Amodio
2017-05-14 01:48:07 -04:00
parent ee29596d45
commit 1acc183621
43 changed files with 2366 additions and 1761 deletions

View File

@@ -1,31 +1,33 @@
'use strict'; 'use strict';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorTracker } from '../activeEditorTracker'; import { ActiveEditorTracker } from '../activeEditorTracker';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { TextEditorComparer, UriComparer } from '../comparers'; import { TextEditorComparer, UriComparer } from '../comparers';
import { GitService } from '../gitService'; import { GitService } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface CloseUnchangedFilesCommandArgs {
uris?: Uri[];
}
export class CloseUnchangedFilesCommand extends ActiveEditorCommand { export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.CloseUnchangedFiles); super(Commands.CloseUnchangedFiles);
} }
async execute(editor: TextEditor, uri?: Uri, uris?: Uri[]) { async execute(editor: TextEditor, uri?: Uri, args: CloseUnchangedFilesCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
if (!uris) { if (args.uris === undefined) {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to close unchanged files`); if (repoPath === undefined) return window.showWarningMessage(`Unable to close unchanged files`);
const status = await this.git.getStatusForRepo(repoPath); const status = await this.git.getStatusForRepo(repoPath);
if (!status) return window.showWarningMessage(`Unable to close unchanged files`); if (status === undefined) return window.showWarningMessage(`Unable to close unchanged files`);
uris = status.files.map(_ => _.Uri); args.uris = status.files.map(_ => _.Uri);
} }
const editorTracker = new ActiveEditorTracker(); const editorTracker = new ActiveEditorTracker();
@@ -35,7 +37,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
do { do {
if (editor !== undefined) { if (editor !== undefined) {
if ((editor.document !== undefined && editor.document.isDirty) || if ((editor.document !== undefined && editor.document.isDirty) ||
uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri))) { args.uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri))) {
// If we didn't start with a valid editor, set one once we find it // If we didn't start with a valid editor, set one once we find it
if (active === undefined) { if (active === undefined) {
active = editor; active = editor;

View File

@@ -1,5 +1,5 @@
'use strict'; 'use strict';
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode'; import { commands, Disposable, TextDocumentShowOptions, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { Telemetry } from '../telemetry'; import { Telemetry } from '../telemetry';
@@ -48,6 +48,12 @@ export const Commands = {
ToggleCodeLens: 'gitlens.toggleCodeLens' as Commands ToggleCodeLens: 'gitlens.toggleCodeLens' as Commands
}; };
export function getCommandUri(uri?: Uri, editor?: TextEditor): Uri | undefined {
if (uri instanceof Uri) return uri;
if (editor === undefined || editor.document === undefined) return undefined;
return editor.document.uri;
}
export type CommandContext = 'gitlens:canToggleCodeLens' | 'gitlens:enabled' | 'gitlens:hasRemotes' | 'gitlens:isBlameable' | 'gitlens:isRepository' | 'gitlens:isTracked' | 'gitlens:key'; export type CommandContext = 'gitlens:canToggleCodeLens' | 'gitlens:enabled' | 'gitlens:hasRemotes' | 'gitlens:isBlameable' | 'gitlens:isRepository' | 'gitlens:isTracked' | 'gitlens:key';
export const CommandContext = { export const CommandContext = {
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext, CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
@@ -140,12 +146,16 @@ export abstract class ActiveEditorCachedCommand extends ActiveEditorCommand {
abstract execute(editor: TextEditor, ...args: any[]): any; abstract execute(editor: TextEditor, ...args: any[]): any;
} }
export async function openEditor(uri: Uri, pinned: boolean = false) { export async function openEditor(uri: Uri, options?: TextDocumentShowOptions): Promise<TextEditor | undefined> {
try { try {
if (!pinned) return await commands.executeCommand(BuiltInCommands.Open, uri); const defaults: TextDocumentShowOptions = {
preserveFocus: false,
preview: true,
viewColumn: (window.activeTextEditor && window.activeTextEditor.viewColumn) || 1
};
const document = await workspace.openTextDocument(uri); const document = await workspace.openTextDocument(uri);
return window.showTextDocument(document, (window.activeTextEditor && window.activeTextEditor.viewColumn) || 1, true); return window.showTextDocument(document, { ...defaults, ...(options || {}) });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'openEditor'); Logger.error(ex, 'openEditor');

View File

@@ -1,40 +1,43 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { copy } from 'copy-paste'; import { copy } from 'copy-paste';
export interface CopyMessageToClipboardCommandArgs {
message?: string;
sha?: string;
}
export class CopyMessageToClipboardCommand extends ActiveEditorCommand { export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.CopyMessageToClipboard); super(Commands.CopyMessageToClipboard);
} }
async execute(editor: TextEditor, uri?: Uri, sha?: string, message?: string): Promise<any> { async execute(editor: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
// If we don't have an editor then get the message of the last commit to the branch // If we don't have an editor then get the message of the last commit to the branch
if (!uri) { if (uri === undefined) {
if (!this.git.repoPath) return undefined; if (!this.git.repoPath) return undefined;
const log = await this.git.getLogForRepo(this.git.repoPath, undefined, 1); const log = await this.git.getLogForRepo(this.git.repoPath, undefined, 1);
if (!log) return undefined; if (!log) return undefined;
message = Iterables.first(log.commits.values()).message; args.message = Iterables.first(log.commits.values()).message;
copy(message); copy(args.message);
return undefined; return undefined;
} }
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (!message) { if (args.message === undefined) {
if (!sha) { if (args.sha === undefined) {
if (editor && editor.document && editor.document.isDirty) return undefined; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const line = (editor && editor.selection.active.line) || gitUri.offset; const line = (editor && editor.selection.active.line) || gitUri.offset;
const blameline = line - gitUri.offset; const blameline = line - gitUri.offset;
@@ -46,7 +49,7 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
if (blame.commit.isUncommitted) return undefined; if (blame.commit.isUncommitted) return undefined;
sha = blame.commit.sha; args.sha = blame.commit.sha;
if (!gitUri.repoPath) { if (!gitUri.repoPath) {
gitUri.repoPath = blame.commit.repoPath; gitUri.repoPath = blame.commit.repoPath;
} }
@@ -58,13 +61,13 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
} }
// Get the full commit message -- since blame only returns the summary // Get the full commit message -- since blame only returns the summary
const commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, sha); const commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, args.sha);
if (!commit) return undefined; if (!commit) return undefined;
message = commit.message; args.message = commit.message;
} }
copy(message); copy(args.message);
return undefined; return undefined;
} }
catch (ex) { catch (ex) {

View File

@@ -1,39 +1,41 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { copy } from 'copy-paste'; import { copy } from 'copy-paste';
export interface CopyShaToClipboardCommandArgs {
sha?: string;
}
export class CopyShaToClipboardCommand extends ActiveEditorCommand { export class CopyShaToClipboardCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.CopyShaToClipboard); super(Commands.CopyShaToClipboard);
} }
async execute(editor: TextEditor, uri?: Uri, sha?: string): Promise<any> { async execute(editor: TextEditor, uri?: Uri, args: CopyShaToClipboardCommandArgs = {}): Promise<any> {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
// If we don't have an editor then get the sha of the last commit to the branch // If we don't have an editor then get the sha of the last commit to the branch
if (!uri) { if (uri === undefined) {
if (!this.git.repoPath) return undefined; if (!this.git.repoPath) return undefined;
const log = await this.git.getLogForRepo(this.git.repoPath, undefined, 1); const log = await this.git.getLogForRepo(this.git.repoPath, undefined, 1);
if (!log) return undefined; if (!log) return undefined;
sha = Iterables.first(log.commits.values()).sha; args.sha = Iterables.first(log.commits.values()).sha;
copy(sha); copy(args.sha);
return undefined; return undefined;
} }
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (!sha) { if (args.sha === undefined) {
if (editor && editor.document && editor.document.isDirty) return undefined; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const line = (editor && editor.selection.active.line) || gitUri.offset; const line = (editor && editor.selection.active.line) || gitUri.offset;
const blameline = line - gitUri.offset; const blameline = line - gitUri.offset;
@@ -43,7 +45,7 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return undefined; if (!blame) return undefined;
sha = blame.commit.sha; args.sha = blame.commit.sha;
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'CopyShaToClipboardCommand', `getBlameForLine(${blameline})`); Logger.error(ex, 'CopyShaToClipboardCommand', `getBlameForLine(${blameline})`);
@@ -51,7 +53,7 @@ export class CopyShaToClipboardCommand extends ActiveEditorCommand {
} }
} }
copy(sha); copy(args.sha);
return undefined; return undefined;
} }
catch (ex) { catch (ex) {

View File

@@ -1,51 +1,53 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitService } from '../gitService'; import { GitService } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks'; import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
export interface DiffDirectoryCommandCommandArgs {
shaOrBranch1?: string;
shaOrBranch2?: string;
}
export class DiffDirectoryCommand extends ActiveEditorCommand { export class DiffDirectoryCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffDirectory); super(Commands.DiffDirectory);
} }
async execute(editor: TextEditor, uri?: Uri, shaOrBranch1?: string, shaOrBranch2?: string): Promise<any> { async execute(editor: TextEditor, uri?: Uri, args: DiffDirectoryCommandCommandArgs = {}): Promise<any> {
const diffTool = await this.git.getConfig('diff.tool'); const diffTool = await this.git.getConfig('diff.tool');
if (!diffTool) { if (!diffTool) {
const result = await window.showWarningMessage(`Unable to open directory compare because there is no Git diff tool configured`, 'View Git Docs'); const result = await window.showWarningMessage(`Unable to open directory compare because there is no Git diff tool configured`, 'View Git Docs');
if (!result) return undefined; if (!result) return undefined;
return commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://git-scm.com/docs/git-config#git-config-difftool')); return commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://git-scm.com/docs/git-config#git-config-difftool'));
} }
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to open directory compare`); if (!repoPath) return window.showWarningMessage(`Unable to open directory compare`);
if (!shaOrBranch1) { if (!args.shaOrBranch1) {
const branches = await this.git.getBranches(repoPath); const branches = await this.git.getBranches(repoPath);
const current = Iterables.find(branches, _ => _.current); const current = Iterables.find(branches, _ => _.current);
if (current == null) return window.showWarningMessage(`Unable to open directory compare`); if (current == null) return window.showWarningMessage(`Unable to open directory compare`);
const pick = await BranchesQuickPick.show(branches, `Compare ${current.name} to \u2026`); const pick = await BranchesQuickPick.show(branches, `Compare ${current.name} to \u2026`);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
shaOrBranch1 = pick.branch.name; args.shaOrBranch1 = pick.branch.name;
if (!shaOrBranch1) return undefined; if (args.shaOrBranch1 === undefined) return undefined;
} }
this.git.openDirectoryDiff(repoPath, shaOrBranch1, shaOrBranch2); this.git.openDirectoryDiff(repoPath, args.shaOrBranch1, args.shaOrBranch2);
return undefined; return undefined;
} }
catch (ex) { catch (ex) {

View File

@@ -1,51 +1,63 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { DiffWithPreviousCommandArgs } from './diffWithPrevious';
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
import { GitCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import * as path from 'path'; import * as path from 'path';
export interface DiffLineWithPreviousCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffLineWithPreviousCommand extends ActiveEditorCommand { export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffLineWithPrevious); super(Commands.DiffLineWithPrevious);
} }
async execute(editor: TextEditor): Promise<any>; async execute(editor: TextEditor, uri?: Uri, args: DiffLineWithPreviousCommandArgs = {}): Promise<any> {
async execute(editor: TextEditor, uri: Uri): Promise<any>; uri = getCommandUri(uri, editor);
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> { if (uri === undefined) return undefined;
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
line = line || (editor && editor.selection.active.line) || gitUri.offset; args.line = args.line || (editor === undefined ? gitUri.offset : editor.selection.active.line);
if (!commit || GitService.isUncommitted(commit.sha)) { if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
if (editor && editor.document && editor.document.isDirty) return undefined; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const blameline = line - gitUri.offset; const blameline = args.line - gitUri.offset;
if (blameline < 0) return undefined; if (blameline < 0) return undefined;
try { try {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`); if (blame === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
commit = blame.commit; args.commit = blame.commit;
// If we don't have a sha or the current commit matches the blame, show the previous // If we don't have a sha or the current commit matches the blame, show the previous
if (!gitUri.sha || gitUri.sha === commit.sha) { if (gitUri.sha === undefined || gitUri.sha === args.commit.sha) {
return commands.executeCommand(Commands.DiffWithPrevious, new GitUri(uri, commit), undefined, line); return commands.executeCommand(Commands.DiffWithPrevious, new GitUri(uri, args.commit), {
line: args.line,
showOptions: args.showOptions
} as DiffWithPreviousCommandArgs);
} }
// If the line is uncommitted, find the previous commit and treat it as a DiffWithWorking // If the line is uncommitted, find the previous commit and treat it as a DiffWithWorking
if (commit.isUncommitted) { if (args.commit.isUncommitted) {
uri = commit.uri; uri = args.commit.uri;
commit = new GitCommit(commit.type, commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message); args.commit = new GitCommit(args.commit.type, args.commit.repoPath, args.commit.previousSha!, args.commit.previousFileName!, args.commit.author, args.commit.date, args.commit.message);
line = (blame.line.line + 1) + gitUri.offset; args.line = (blame.line.line + 1) + gitUri.offset;
return commands.executeCommand(Commands.DiffWithWorking, uri, commit, line);
return commands.executeCommand(Commands.DiffWithWorking, uri, {
commit: args.commit,
line: args.line,
showOptions: args.showOptions
} as DiffWithWorkingCommandArgs);
} }
} }
catch (ex) { catch (ex) {
@@ -57,11 +69,17 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
try { try {
const [rhs, lhs] = await Promise.all([ const [rhs, lhs] = await Promise.all([
this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha!), this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha!),
this.git.getVersionedFile(commit.repoPath, commit.uri.fsPath, commit.sha) this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha)
]); ]);
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(lhs), Uri.file(rhs), `${path.basename(commit.uri.fsPath)} (${commit.shortSha}) \u2194 ${path.basename(gitUri.fsPath)} (${gitUri.shortSha})`);
await commands.executeCommand(BuiltInCommands.Diff,
Uri.file(lhs),
Uri.file(rhs),
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) \u2194 ${path.basename(gitUri.fsPath)} (${gitUri.shortSha})`,
args.showOptions);
// TODO: Figure out how to focus the left pane // TODO: Figure out how to focus the left pane
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }); return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithPreviousLineCommand', 'getVersionedFile'); Logger.error(ex, 'DiffWithPreviousLineCommand', 'getVersionedFile');

View File

@@ -1,41 +1,44 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
import { GitCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface DiffLineWithWorkingCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffLineWithWorkingCommand extends ActiveEditorCommand { export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffLineWithWorking); super(Commands.DiffLineWithWorking);
} }
async execute(editor: TextEditor): Promise<any>; async execute(editor: TextEditor, uri?: Uri, args: DiffLineWithWorkingCommandArgs = {}): Promise<any> {
async execute(editor: TextEditor, uri: Uri): Promise<any>; uri = getCommandUri(uri, editor);
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> { if (uri === undefined) return undefined;
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
line = line || (editor && editor.selection.active.line) || gitUri.offset; args.line = args.line || (editor === undefined ? gitUri.offset : editor.selection.active.line);
if (!commit || GitService.isUncommitted(commit.sha)) { if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
if (editor && editor.document && editor.document.isDirty) return undefined; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const blameline = line - gitUri.offset; const blameline = args.line - gitUri.offset;
if (blameline < 0) return undefined; if (blameline < 0) return undefined;
try { try {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`); if (blame === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
commit = blame.commit; args.commit = blame.commit;
// If the line is uncommitted, find the previous commit // If the line is uncommitted, find the previous commit
if (commit.isUncommitted) { if (args.commit.isUncommitted) {
commit = new GitCommit(commit.type, commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message); args.commit = new GitCommit(args.commit.type, args.commit.repoPath, args.commit.previousSha!, args.commit.previousFileName!, args.commit.author, args.commit.date, args.commit.message);
line = blame.line.line + 1 + gitUri.offset; args.line = blame.line.line + 1 + gitUri.offset;
} }
} }
catch (ex) { catch (ex) {
@@ -44,6 +47,6 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
} }
} }
return commands.executeCommand(Commands.DiffWithWorking, uri, commit, line); return commands.executeCommand(Commands.DiffWithWorking, uri, args as DiffWithWorkingCommandArgs);
} }
} }

View File

@@ -1,44 +1,54 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks'; import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
import * as path from 'path'; import * as path from 'path';
export interface DiffWithBranchCommandArgs {
line?: number;
showOptions?: TextDocumentShowOptions;
goBackCommand?: CommandQuickPickItem;
}
export class DiffWithBranchCommand extends ActiveEditorCommand { export class DiffWithBranchCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffWithBranch); super(Commands.DiffWithBranch);
} }
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem): Promise<any> { async execute(editor: TextEditor, uri?: Uri, args: DiffWithBranchCommandArgs = {}): Promise<any> {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
const line = (editor && editor.selection.active.line) || 0; args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (gitUri.repoPath === undefined) return undefined; if (gitUri.repoPath === undefined) return undefined;
const branches = await this.git.getBranches(gitUri.repoPath); const branches = await this.git.getBranches(gitUri.repoPath);
const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, goBackCommand); const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, args.goBackCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
const branch = pick.branch.name; const branch = pick.branch.name;
if (!branch) return undefined; if (branch === undefined) return undefined;
try { try {
const compare = await this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, branch); const compare = await this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, branch);
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), gitUri.fileUri(), `${path.basename(gitUri.fsPath)} (${branch}) \u2194 ${path.basename(gitUri.fsPath)}`);
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }); await commands.executeCommand(BuiltInCommands.Diff,
Uri.file(compare),
gitUri.fileUri(),
`${path.basename(gitUri.fsPath)} (${branch}) \u2194 ${path.basename(gitUri.fsPath)}`,
args.showOptions);
// TODO: Figure out how to focus the left pane
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithBranchCommand', 'getVersionedFile'); Logger.error(ex, 'DiffWithBranchCommand', 'getVersionedFile');

View File

@@ -1,51 +1,46 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { commands, Range, TextEditor, Uri, window } from 'vscode'; import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitLogCommit, GitService, GitUri } from '../gitService'; import { GitLogCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import * as path from 'path'; import * as path from 'path';
export interface DiffWithNextCommandArgs {
commit?: GitLogCommit;
line?: number;
range?: Range;
showOptions?: TextDocumentShowOptions;
}
export class DiffWithNextCommand extends ActiveEditorCommand { export class DiffWithNextCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffWithNext); super(Commands.DiffWithNext);
} }
async execute(editor: TextEditor): Promise<any>; async execute(editor: TextEditor, uri?: Uri, args: DiffWithNextCommandArgs = {}): Promise<any> {
async execute(editor: TextEditor, uri: Uri): Promise<any>; uri = getCommandUri(uri, editor);
async execute(editor: TextEditor, uri: Uri, commit: GitLogCommit, range?: Range): Promise<any>; if (uri === undefined) return undefined;
async execute(editor: TextEditor, uri: Uri, commit: GitLogCommit, line?: number): Promise<any>;
async execute(editor: TextEditor, uri?: Uri, commit?: GitLogCommit, rangeOrLine?: Range | number): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
let line = (editor && editor.selection.active.line) || 0; args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
if (typeof rangeOrLine === 'number') {
line = rangeOrLine || line;
rangeOrLine = undefined;
}
if (!commit || !(commit instanceof GitLogCommit) || rangeOrLine instanceof Range) { if (args.commit === undefined || !(args.commit instanceof GitLogCommit) || args.range !== undefined) {
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
if (!gitUri.sha) { // If the sha is missing or the file is uncommitted, treat it as a DiffWithWorking
// If the file is uncommitted, treat it as a DiffWithWorking if (gitUri.sha === undefined && await this.git.isFileUncommitted(gitUri)) {
if (await this.git.isFileUncommitted(gitUri)) { return commands.executeCommand(Commands.DiffWithWorking, uri);
return commands.executeCommand(Commands.DiffWithWorking, uri);
}
} }
const sha = (commit && commit.sha) || gitUri.sha; const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, rangeOrLine!); const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, args.range!);
if (!log) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`); if (log === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values()); args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithNextCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`); Logger.error(ex, 'DiffWithNextCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);
@@ -53,17 +48,22 @@ export class DiffWithNextCommand extends ActiveEditorCommand {
} }
} }
if (!commit.nextSha) { if (args.commit.nextSha === undefined) return commands.executeCommand(Commands.DiffWithWorking, uri);
return commands.executeCommand(Commands.DiffWithWorking, uri);
}
try { try {
const [rhs, lhs] = await Promise.all([ const [rhs, lhs] = await Promise.all([
this.git.getVersionedFile(commit.repoPath, commit.nextUri.fsPath, commit.nextSha), this.git.getVersionedFile(args.commit.repoPath, args.commit.nextUri.fsPath, args.commit.nextSha),
this.git.getVersionedFile(commit.repoPath, commit.uri.fsPath, commit.sha) this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha)
]); ]);
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(lhs), Uri.file(rhs), `${path.basename(commit.uri.fsPath)} (${commit.shortSha}) \u2194 ${path.basename(commit.nextUri.fsPath)} (${commit.nextShortSha})`);
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }); await commands.executeCommand(BuiltInCommands.Diff,
Uri.file(lhs),
Uri.file(rhs),
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) \u2194 ${path.basename(args.commit.nextUri.fsPath)} (${args.commit.nextShortSha})`,
args.showOptions);
// TODO: Figure out how to focus the left pane
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithNextCommand', 'getVersionedFile'); Logger.error(ex, 'DiffWithNextCommand', 'getVersionedFile');

View File

@@ -1,52 +1,47 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { commands, Range, TextEditor, Uri, window } from 'vscode'; import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import * as moment from 'moment'; import * as moment from 'moment';
import * as path from 'path'; import * as path from 'path';
export interface DiffWithPreviousCommandArgs {
commit?: GitCommit;
line?: number;
range?: Range;
showOptions?: TextDocumentShowOptions;
}
export class DiffWithPreviousCommand extends ActiveEditorCommand { export class DiffWithPreviousCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffWithPrevious); super(Commands.DiffWithPrevious);
} }
async execute(editor: TextEditor): Promise<any>; async execute(editor: TextEditor, uri?: Uri, args: DiffWithPreviousCommandArgs = {}): Promise<any> {
async execute(editor: TextEditor, uri: Uri): Promise<any>; uri = getCommandUri(uri, editor);
async execute(editor: TextEditor, uri: Uri, commit: GitCommit, range?: Range): Promise<any>; if (uri === undefined) return undefined;
async execute(editor: TextEditor, uri: Uri, commit: GitCommit, line?: number): Promise<any>;
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, rangeOrLine?: Range | number): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
let line = (editor && editor.selection.active.line) || 0; args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
if (typeof rangeOrLine === 'number') {
line = rangeOrLine || line;
rangeOrLine = undefined;
}
if (!commit || rangeOrLine instanceof Range) { if (args.commit === undefined || args.range !== undefined) {
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
if (!gitUri.sha) { // If the sha is missing or the file is uncommitted, treat it as a DiffWithWorking
// If the file is uncommitted, treat it as a DiffWithWorking if (gitUri.sha === undefined && await this.git.isFileUncommitted(gitUri)) {
if (await this.git.isFileUncommitted(gitUri)) { return commands.executeCommand(Commands.DiffWithWorking, uri);
return commands.executeCommand(Commands.DiffWithWorking, uri);
}
} }
const sha = (commit && commit.sha) || gitUri.sha; const sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, rangeOrLine!); const log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, undefined, sha ? undefined : 2, args.range!);
if (!log) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`); if (log === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values()); args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`); Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);
@@ -54,18 +49,22 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
} }
} }
if (!commit.previousSha) { if (args.commit.previousSha === undefined) return window.showInformationMessage(`Commit ${args.commit.shortSha} (${args.commit.author}, ${moment(args.commit.date).fromNow()}) has no previous commit`);
return window.showInformationMessage(`Commit ${commit.shortSha} (${commit.author}, ${moment(commit.date).fromNow()}) has no previous commit`);
}
try { try {
const [rhs, lhs] = await Promise.all([ const [rhs, lhs] = await Promise.all([
this.git.getVersionedFile(commit.repoPath, commit.uri.fsPath, commit.sha), this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha),
this.git.getVersionedFile(commit.repoPath, commit.previousUri.fsPath, commit.previousSha) this.git.getVersionedFile(args.commit.repoPath, args.commit.previousUri.fsPath, args.commit.previousSha)
]); ]);
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(lhs), Uri.file(rhs), `${path.basename(commit.previousUri.fsPath)} (${commit.previousShortSha}) \u2194 ${path.basename(commit.uri.fsPath)} (${commit.shortSha})`);
await commands.executeCommand(BuiltInCommands.Diff,
Uri.file(lhs),
Uri.file(rhs),
`${path.basename(args.commit.previousUri.fsPath)} (${args.commit.previousShortSha}) \u2194 ${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha})`,
args.showOptions);
// TODO: Figure out how to focus the left pane // TODO: Figure out how to focus the left pane
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }); return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithPreviousCommand', 'getVersionedFile'); Logger.error(ex, 'DiffWithPreviousCommand', 'getVersionedFile');

View File

@@ -1,34 +1,35 @@
'use strict'; 'use strict';
// import { Iterables } from '../system'; import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { commands, TextEditor, Uri, window } from 'vscode'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { ActiveEditorCommand, Commands } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import * as path from 'path'; import * as path from 'path';
export interface DiffWithWorkingCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffWithWorkingCommand extends ActiveEditorCommand { export class DiffWithWorkingCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.DiffWithWorking); super(Commands.DiffWithWorking);
} }
async execute(editor: TextEditor): Promise<any>; async execute(editor: TextEditor, uri?: Uri, args: DiffWithWorkingCommandArgs = {}): Promise<any> {
async execute(editor: TextEditor, uri: Uri): Promise<any>; uri = getCommandUri(uri, editor);
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> { if (uri === undefined) return undefined;
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
line = line || (editor && editor.selection.active.line) || 0; args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line);
if (!commit || GitService.isUncommitted(commit.sha)) { if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true }); args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
if (!commit) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`); if (args.commit === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithWorkingCommand', `getLogCommit(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`); Logger.error(ex, 'DiffWithWorkingCommand', `getLogCommit(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`);
@@ -42,9 +43,16 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
if (workingFileName === undefined) return undefined; if (workingFileName === undefined) return undefined;
try { try {
const compare = await this.git.getVersionedFile(commit.repoPath, commit.uri.fsPath, commit.sha); const compare = await this.git.getVersionedFile(args.commit.repoPath, args.commit.uri.fsPath, args.commit.sha);
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), Uri.file(path.resolve(gitUri.repoPath, workingFileName)), `${path.basename(commit.uri.fsPath)} (${commit.shortSha}) \u2194 ${path.basename(workingFileName)}`);
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }); await commands.executeCommand(BuiltInCommands.Diff,
Uri.file(compare),
Uri.file(path.resolve(gitUri.repoPath, workingFileName)),
`${path.basename(args.commit.uri.fsPath)} (${args.commit.shortSha}) \u2194 ${path.basename(workingFileName)}`,
args.showOptions);
// TODO: Figure out how to focus the left pane
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'DiffWithWorkingCommand', 'getVersionedFile'); Logger.error(ex, 'DiffWithWorkingCommand', 'getVersionedFile');

View File

@@ -1,142 +1,137 @@
'use strict'; 'use strict';
import { commands, Disposable, QuickPickItem } from 'vscode'; import { commands, Disposable } from 'vscode';
import { CommandContext, setCommandContext } from './common'; import { CommandContext, setCommandContext } from './common';
import { ExtensionKey } from '../constants'; import { ExtensionKey } from '../constants';
import { CommandQuickPickItem, OpenFileCommandQuickPickItem } from '../quickPicks'; import { QuickPickItem } from '../quickPicks';
import { Logger } from '../logger'; import { Logger } from '../logger';
const keyNoopCommand = Object.create(null) as QuickPickItem; const keyNoopCommand = Object.create(null) as QuickPickItem;
export { keyNoopCommand as KeyNoopCommand }; export { keyNoopCommand as KeyNoopCommand };
export declare type Keys = 'left' | 'right' | ',' | '.'; export declare type Keys = 'left' | 'right' | ',' | '.';
export const keys: Keys[] = [ export const keys: Keys[] = [
'left', 'left',
'right', 'right',
',', ',',
'.' '.'
]; ];
export declare type KeyMapping = { [id: string]: (QuickPickItem | (() => Promise<QuickPickItem>) | undefined) }; export declare type KeyMapping = { [id: string]: (QuickPickItem | (() => Promise<QuickPickItem>) | undefined) };
let mappings: KeyMapping[] = []; let mappings: KeyMapping[] = [];
let _instance: Keyboard; let _instance: Keyboard;
export class KeyboardScope extends Disposable { export class KeyboardScope extends Disposable {
constructor(private mapping: KeyMapping) { constructor(private mapping: KeyMapping) {
super(() => this.dispose()); super(() => this.dispose());
for (const key in mapping) { for (const key in mapping) {
mapping[key] = mapping[key] || keyNoopCommand; mapping[key] = mapping[key] || keyNoopCommand;
} }
} }
async dispose() { async dispose() {
const index = mappings.indexOf(this.mapping); const index = mappings.indexOf(this.mapping);
Logger.log('KeyboardScope.dispose', mappings.length, index); Logger.log('KeyboardScope.dispose', mappings.length, index);
if (index === (mappings.length - 1)) { if (index === (mappings.length - 1)) {
mappings.pop(); mappings.pop();
await this.updateKeyCommandsContext(mappings[mappings.length - 1]); await this.updateKeyCommandsContext(mappings[mappings.length - 1]);
} }
else { else {
mappings.splice(index, 1); mappings.splice(index, 1);
} }
} }
async begin() { async begin() {
mappings.push(this.mapping); mappings.push(this.mapping);
await this.updateKeyCommandsContext(this.mapping); await this.updateKeyCommandsContext(this.mapping);
return this; return this;
} }
async clearKeyCommand(key: Keys) { async clearKeyCommand(key: Keys) {
const mapping = mappings[mappings.length - 1]; const mapping = mappings[mappings.length - 1];
if (mapping !== this.mapping || !mapping[key]) return; if (mapping !== this.mapping || !mapping[key]) return;
Logger.log('KeyboardScope.clearKeyCommand', mappings.length, key); Logger.log('KeyboardScope.clearKeyCommand', mappings.length, key);
mapping[key] = undefined; mapping[key] = undefined;
await setCommandContext(`${CommandContext.Key}:${key}`, false); await setCommandContext(`${CommandContext.Key}:${key}`, false);
} }
async setKeyCommand(key: Keys, command: QuickPickItem | (() => Promise<QuickPickItem>)) { async setKeyCommand(key: Keys, command: QuickPickItem | (() => Promise<QuickPickItem>)) {
const mapping = mappings[mappings.length - 1]; const mapping = mappings[mappings.length - 1];
if (mapping !== this.mapping) return; if (mapping !== this.mapping) return;
Logger.log('KeyboardScope.setKeyCommand', mappings.length, key, !!mapping[key]); Logger.log('KeyboardScope.setKeyCommand', mappings.length, key, !!mapping[key]);
if (!mapping[key]) { if (!mapping[key]) {
mapping[key] = command; mapping[key] = command;
await setCommandContext(`${CommandContext.Key}:${key}`, true); await setCommandContext(`${CommandContext.Key}:${key}`, true);
} }
else { else {
mapping[key] = command; mapping[key] = command;
} }
} }
private async updateKeyCommandsContext(mapping: KeyMapping) { private async updateKeyCommandsContext(mapping: KeyMapping) {
const promises = []; const promises = [];
for (const key of keys) { for (const key of keys) {
promises.push(setCommandContext(`${CommandContext.Key}:${key}`, !!(mapping && mapping[key]))); promises.push(setCommandContext(`${CommandContext.Key}:${key}`, !!(mapping && mapping[key])));
} }
await Promise.all(promises); await Promise.all(promises);
} }
} }
export class Keyboard extends Disposable { export class Keyboard extends Disposable {
static get instance(): Keyboard { static get instance(): Keyboard {
return _instance; return _instance;
} }
private _disposable: Disposable; private _disposable: Disposable;
constructor() { constructor() {
super(() => this.dispose()); super(() => this.dispose());
const subscriptions: Disposable[] = []; const subscriptions: Disposable[] = [];
for (const key of keys) { for (const key of keys) {
subscriptions.push(commands.registerCommand(`${ExtensionKey}.key.${key}`, () => this.execute(key), this)); subscriptions.push(commands.registerCommand(`${ExtensionKey}.key.${key}`, () => this.execute(key), this));
} }
this._disposable = Disposable.from(...subscriptions); this._disposable = Disposable.from(...subscriptions);
_instance = this; _instance = this;
} }
dispose() { dispose() {
this._disposable && this._disposable.dispose(); this._disposable && this._disposable.dispose();
} }
async beginScope(mapping?: KeyMapping): Promise<KeyboardScope> { async beginScope(mapping?: KeyMapping): Promise<KeyboardScope> {
Logger.log('Keyboard.beginScope', mappings.length); Logger.log('Keyboard.beginScope', mappings.length);
return await new KeyboardScope(mapping ? Object.assign(Object.create(null), mapping) : Object.create(null)).begin(); return await new KeyboardScope(mapping ? Object.assign(Object.create(null), mapping) : Object.create(null)).begin();
} }
async execute(key: Keys): Promise<{} | undefined> { async execute(key: Keys): Promise<{} | undefined> {
if (!mappings.length) return undefined; if (!mappings.length) return undefined;
try { try {
const mapping = mappings[mappings.length - 1]; const mapping = mappings[mappings.length - 1];
let command = mapping[key] as CommandQuickPickItem | (() => Promise<CommandQuickPickItem>); let command = mapping[key] as QuickPickItem | (() => Promise<QuickPickItem>);
if (typeof command === 'function') { if (typeof command === 'function') {
command = await command(); command = await command();
} }
if (!command || !(command instanceof CommandQuickPickItem)) return undefined; if (!command || typeof command.onDidPressKey !== 'function') return undefined;
Logger.log('Keyboard.execute', key); Logger.log('Keyboard.execute', key);
if (command instanceof OpenFileCommandQuickPickItem) { return await command.onDidPressKey(key);
// Have to open this pinned right now, because vscode doesn't have a way to open a unpinned, but unfocused editor }
return await command.execute(true); catch (ex) {
} Logger.error(ex, 'Keyboard.execute');
return undefined;
return await command.execute(); }
} }
catch (ex) {
Logger.error(ex, 'Keyboard.execute');
return undefined;
}
}
} }

View File

@@ -1,33 +1,35 @@
'use strict'; 'use strict';
import { TextEditor, Uri, window } from 'vscode'; import { TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, openEditor } from './common'; import { ActiveEditorCommand, Commands, getCommandUri, openEditor } from './common';
import { GitService } from '../gitService'; import { GitService } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface OpenChangedFilesCommandArgs {
uris?: Uri[];
}
export class OpenChangedFilesCommand extends ActiveEditorCommand { export class OpenChangedFilesCommand extends ActiveEditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.OpenChangedFiles); super(Commands.OpenChangedFiles);
} }
async execute(editor: TextEditor, uri?: Uri, uris?: Uri[]) { async execute(editor: TextEditor, uri?: Uri, args: OpenChangedFilesCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
if (!uris) { if (args.uris === undefined) {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to open changed files`); if (repoPath === undefined) return window.showWarningMessage(`Unable to open changed files`);
const status = await this.git.getStatusForRepo(repoPath); const status = await this.git.getStatusForRepo(repoPath);
if (!status) return window.showWarningMessage(`Unable to open changed files`); if (status === undefined) return window.showWarningMessage(`Unable to open changed files`);
uris = status.files.filter(_ => _.status !== 'D').map(_ => _.Uri); args.uris = status.files.filter(_ => _.status !== 'D').map(_ => _.Uri);
} }
for (const uri of uris) { for (const uri of args.uris) {
await openEditor(uri, true); await openEditor(uri, { preserveFocus: true, preview: false } as TextDocumentShowOptions);
} }
return undefined; return undefined;

View File

@@ -1,9 +1,10 @@
'use strict'; 'use strict';
import { Arrays } from '../system'; import { Arrays } from '../system';
import { commands, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { commands, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitCommit, GitService, GitUri } from '../gitService'; import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { OpenInRemoteCommandArgs } from './openInRemote';
export class OpenCommitInRemoteCommand extends ActiveEditorCommand { export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
@@ -12,24 +13,21 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
}
if ((editor && editor.document && editor.document.isDirty) || !uri) return undefined;
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (!gitUri.repoPath) return undefined; if (!gitUri.repoPath) return undefined;
const line = (editor && editor.selection.active.line) || gitUri.offset; const line = editor === undefined ? gitUri.offset : editor.selection.active.line;
try { try {
const blameline = line - gitUri.offset; const blameline = line - gitUri.offset;
if (blameline < 0) return undefined; if (blameline < 0) return undefined;
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return window.showWarningMessage(`Unable to open commit in remote provider. File is probably not under source control`); if (blame === undefined) return window.showWarningMessage(`Unable to open commit in remote provider. File is probably not under source control`);
let commit = blame.commit; let commit = blame.commit;
// If the line is uncommitted, find the previous commit // If the line is uncommitted, find the previous commit
@@ -38,7 +36,13 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
} }
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
return commands.executeCommand(Commands.OpenInRemote, uri, remotes, 'commit', [commit.sha]); return commands.executeCommand(Commands.OpenInRemote, uri, {
resource: {
type: 'commit',
sha: commit.sha
},
remotes
} as OpenInRemoteCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'OpenCommitInRemoteCommand'); Logger.error(ex, 'OpenCommitInRemoteCommand');

View File

@@ -1,9 +1,10 @@
'use strict'; 'use strict';
import { Arrays } from '../system'; import { Arrays } from '../system';
import { commands, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { commands, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { OpenInRemoteCommandArgs } from './openInRemote';
export class OpenFileInRemoteCommand extends ActiveEditorCommand { export class OpenFileInRemoteCommand extends ActiveEditorCommand {
@@ -12,12 +13,8 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
if (!uri) return undefined;
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (!gitUri.repoPath) return undefined; if (!gitUri.repoPath) return undefined;
@@ -26,8 +23,18 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
try { try {
const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await this.git.getRemotes(gitUri.repoPath), _ => _.url, _ => !!_.provider);
const range = editor && new Range(editor.selection.start.with({ line: editor.selection.start.line + 1 }), editor.selection.end.with({ line: editor.selection.end.line + 1 })); const range = editor === undefined ? undefined : new Range(editor.selection.start.with({ line: editor.selection.start.line + 1 }), editor.selection.end.with({ line: editor.selection.end.line + 1 }));
return commands.executeCommand(Commands.OpenInRemote, uri, remotes, 'file', [gitUri.getRelativePath(), branch === undefined ? 'Current' : branch.name, gitUri.sha, range]);
return commands.executeCommand(Commands.OpenInRemote, uri, {
resource: {
type: 'file',
branch: branch === undefined ? 'Current' : branch.name,
fileName: gitUri.getRelativePath(),
range: range,
sha: gitUri.sha
},
remotes
} as OpenInRemoteCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'OpenFileInRemoteCommand'); Logger.error(ex, 'OpenFileInRemoteCommand');

View File

@@ -1,50 +1,73 @@
'use strict'; 'use strict';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common'; import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitRemote, RemoteOpenType } from '../gitService'; import { GitLogCommit, GitRemote, RemoteResource } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, OpenRemoteCommandQuickPickItem, RemotesQuickPick } from '../quickPicks'; import { CommandQuickPickItem, OpenRemoteCommandQuickPickItem, RemotesQuickPick } from '../quickPicks';
export interface OpenInRemoteCommandArgs {
remotes?: GitRemote[];
resource?: RemoteResource;
goBackCommand?: CommandQuickPickItem;
}
export class OpenInRemoteCommand extends ActiveEditorCommand { export class OpenInRemoteCommand extends ActiveEditorCommand {
constructor() { constructor() {
super(Commands.OpenInRemote); super(Commands.OpenInRemote);
} }
async execute(editor: TextEditor, uri?: Uri, remotes?: GitRemote[], type?: RemoteOpenType, args: string[] = [], goBackCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: OpenInRemoteCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
if (remotes === undefined) return undefined; if (args.remotes === undefined || args.resource === undefined) return undefined;
if (type === undefined) throw new Error(`Invalid type ${type}`);
if (remotes.length === 1) { if (args.remotes.length === 1) {
const command = new OpenRemoteCommandQuickPickItem(remotes[0], type, ...args); const command = new OpenRemoteCommandQuickPickItem(args.remotes[0], args.resource);
return command.execute(); return command.execute();
} }
let placeHolder: string = ''; let placeHolder: string = '';
switch (type) { switch (args.resource.type) {
case 'branch': case 'branch':
placeHolder = `open ${args[0]} branch in\u2026`; placeHolder = `open ${args.resource.branch} branch in\u2026`;
break; break;
case 'commit': case 'commit':
const shortSha = args[0].substring(0, 8); const shortSha = args.resource.sha.substring(0, 8);
placeHolder = `open commit ${shortSha} in\u2026`; placeHolder = `open commit ${shortSha} in\u2026`;
break; break;
case 'file':
case 'working-file':
const shortFileSha = (args[2] && args[2].substring(0, 8)) || '';
const shaSuffix = shortFileSha ? ` \u00a0\u2022\u00a0 ${shortFileSha}` : '';
placeHolder = `open ${args[0]}${shaSuffix} in\u2026`; case 'file':
if (args.resource.commit !== undefined && args.resource.commit instanceof GitLogCommit) {
if (args.resource.commit.status === 'D') {
args.resource.sha = args.resource.commit.previousSha;
placeHolder = `open ${args.resource.fileName} \u00a0\u2022\u00a0 ${args.resource.commit.previousShortSha} in\u2026`;
}
else {
args.resource.sha = args.resource.commit.sha;
placeHolder = `open ${args.resource.fileName} \u00a0\u2022\u00a0 ${args.resource.commit.shortSha} in\u2026`;
}
}
else {
const shortFileSha = args.resource.sha === undefined ? '' : args.resource.sha.substring(0, 8);
const shaSuffix = shortFileSha ? ` \u00a0\u2022\u00a0 ${shortFileSha}` : '';
placeHolder = `open ${args.resource.fileName}${shaSuffix} in\u2026`;
}
break;
case 'working-file':
placeHolder = `open ${args.resource.fileName} in\u2026`;
break; break;
} }
const pick = await RemotesQuickPick.show(remotes, placeHolder, type, args, goBackCommand); const pick = await RemotesQuickPick.show(args.remotes, placeHolder, args.resource, args.goBackCommand);
return pick && pick.execute(); if (pick === undefined) return undefined;
return pick.execute();
} }
catch (ex) { catch (ex) {

View File

@@ -4,19 +4,21 @@ import { BlameAnnotationController } from '../blameAnnotationController';
import { Commands, EditorCommand } from './common'; import { Commands, EditorCommand } from './common';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface ShowBlameCommandArgs {
sha?: string;
}
export class ShowBlameCommand extends EditorCommand { export class ShowBlameCommand extends EditorCommand {
constructor(private annotationController: BlameAnnotationController) { constructor(private annotationController: BlameAnnotationController) {
super(Commands.ShowBlame); super(Commands.ShowBlame);
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string): Promise<any> { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ShowBlameCommandArgs = {}): Promise<any> {
try { if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
if (sha) {
return this.annotationController.showBlameAnnotation(editor, sha);
}
return this.annotationController.showBlameAnnotation(editor, editor.selection.active.line); try {
return this.annotationController.showBlameAnnotation(editor, args.sha !== undefined ? args.sha : editor.selection.active.line);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowBlameCommand'); Logger.error(ex, 'ShowBlameCommand');

View File

@@ -1,35 +1,40 @@
'use strict'; 'use strict';
import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
import { Commands, EditorCommand } from './common'; import { Commands, EditorCommand, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface ShowBlameHistoryCommandArgs {
line?: number;
position?: Position;
range?: Range;
sha?: string;
}
export class ShowBlameHistoryCommand extends EditorCommand { export class ShowBlameHistoryCommand extends EditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowBlameHistory); super(Commands.ShowBlameHistory);
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, range?: Range, position?: Position, sha?: string, line?: number) { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ShowBlameHistoryCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
if (range == null || position == null) { if (args.range == null || args.position == null) {
// If the command is executed manually -- treat it as a click on the root lens (i.e. show blame for the whole file) // If the command is executed manually -- treat it as a click on the root lens (i.e. show blame for the whole file)
range = editor.document.validateRange(new Range(0, 0, 1000000, 1000000)); args.range = editor.document.validateRange(new Range(0, 0, 1000000, 1000000));
position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start; args.position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start;
} }
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
const locations = await this.git.getBlameLocations(gitUri, range, sha, line); const locations = await this.git.getBlameLocations(gitUri, args.range, args.sha, args.line);
if (!locations) return window.showWarningMessage(`Unable to show blame history. File is probably not under source control`); if (locations === undefined) return window.showWarningMessage(`Unable to show blame history. File is probably not under source control`);
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, position, locations); return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowBlameHistoryCommand', 'getBlameLocations'); Logger.error(ex, 'ShowBlameHistoryCommand', 'getBlameLocations');

View File

@@ -1,9 +1,10 @@
'use strict'; 'use strict';
import { commands, InputBoxOptions, TextEditor, Uri, window } from 'vscode'; import { commands, InputBoxOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitRepoSearchBy, GitService, GitUri } from '../gitService'; import { GitRepoSearchBy, GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, CommitsQuickPick } from '../quickPicks'; import { CommandQuickPickItem, CommitsQuickPick } from '../quickPicks';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
const searchByRegex = /^([@:#])/; const searchByRegex = /^([@:#])/;
const searchByMap = new Map<string, GitRepoSearchBy>([ const searchByMap = new Map<string, GitRepoSearchBy>([
@@ -12,68 +13,73 @@ const searchByMap = new Map<string, GitRepoSearchBy>([
['#', GitRepoSearchBy.Sha] ['#', GitRepoSearchBy.Sha]
]); ]);
export interface ShowCommitSearchCommandArgs {
search?: string;
searchBy?: GitRepoSearchBy;
goBackCommand?: CommandQuickPickItem;
}
export class ShowCommitSearchCommand extends ActiveEditorCachedCommand { export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowCommitSearch); super(Commands.ShowCommitSearch);
} }
async execute(editor: TextEditor, uri?: Uri, search?: string, searchBy?: GitRepoSearchBy, goBackCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowCommitSearchCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (gitUri.repoPath === undefined) return undefined; if (gitUri.repoPath === undefined) return undefined;
if (!search || searchBy == null) { if (!args.search || args.searchBy == null) {
search = await window.showInputBox({ args.search = await window.showInputBox({
value: search, value: args.search,
prompt: `Please enter a search string`, prompt: `Please enter a search string`,
placeHolder: `search by message, author (use @<name>), files (use :<pattern>), or commit id (use #<sha>)` placeHolder: `search by message, author (use @<name>), files (use :<pattern>), or commit id (use #<sha>)`
} as InputBoxOptions); } as InputBoxOptions);
if (search === undefined) return goBackCommand && goBackCommand.execute(); if (args.search === undefined) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
const match = searchByRegex.exec(search); const match = searchByRegex.exec(args.search);
if (match && match[1]) { if (match && match[1]) {
searchBy = searchByMap.get(match[1]); args.searchBy = searchByMap.get(match[1]);
search = search.substring((search[1] === ' ') ? 2 : 1); args.search = args.search.substring((args.search[1] === ' ') ? 2 : 1);
} }
else if (GitService.isSha(search)) { else if (GitService.isSha(args.search)) {
searchBy = GitRepoSearchBy.Sha; args.searchBy = GitRepoSearchBy.Sha;
} }
else { else {
searchBy = GitRepoSearchBy.Message; args.searchBy = GitRepoSearchBy.Message;
} }
} }
try { try {
if (searchBy === undefined) { if (args.searchBy === undefined) {
searchBy = GitRepoSearchBy.Message; args.searchBy = GitRepoSearchBy.Message;
} }
const log = await this.git.getLogForRepoSearch(gitUri.repoPath, search, searchBy); const log = await this.git.getLogForRepoSearch(gitUri.repoPath, args.search, args.searchBy);
if (log === undefined) return undefined; if (log === undefined) return undefined;
let originalSearch: string | undefined = undefined; let originalSearch: string | undefined = undefined;
let placeHolder: string | undefined = undefined; let placeHolder: string | undefined = undefined;
switch (searchBy) { switch (args.searchBy) {
case GitRepoSearchBy.Author: case GitRepoSearchBy.Author:
originalSearch = `@${search}`; originalSearch = `@${args.search}`;
placeHolder = `commits with author matching '${search}'`; placeHolder = `commits with author matching '${args.search}'`;
break; break;
case GitRepoSearchBy.Files: case GitRepoSearchBy.Files:
originalSearch = `:${search}`; originalSearch = `:${args.search}`;
placeHolder = `commits with files matching '${search}'`; placeHolder = `commits with files matching '${args.search}'`;
break; break;
case GitRepoSearchBy.Message: case GitRepoSearchBy.Message:
originalSearch = search; originalSearch = args.search;
placeHolder = `commits with message matching '${search}'`; placeHolder = `commits with message matching '${args.search}'`;
break; break;
case GitRepoSearchBy.Sha: case GitRepoSearchBy.Sha:
originalSearch = `#${search}`; originalSearch = `#${args.search}`;
placeHolder = `commits with id matching '${search}'`; placeHolder = `commits with id matching '${args.search}'`;
break; break;
} }
@@ -81,20 +87,32 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to commit search` description: `\u00a0 \u2014 \u00a0\u00a0 to commit search`
}, Commands.ShowCommitSearch, [gitUri, originalSearch, undefined, goBackCommand]); }, Commands.ShowCommitSearch, [
gitUri,
{
search: originalSearch,
goBackCommand: args.goBackCommand
} as ShowCommitSearchCommandArgs
]);
const pick = await CommitsQuickPick.show(this.git, log, placeHolder!, currentCommand); const pick = await CommitsQuickPick.show(this.git, log, placeHolder!, currentCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return commands.executeCommand(Commands.ShowQuickCommitDetails, new GitUri(pick.commit.uri, pick.commit), pick.commit.sha, pick.commit, return commands.executeCommand(Commands.ShowQuickCommitDetails,
new CommandQuickPickItem({ new GitUri(pick.commit.uri, pick.commit),
label: `go back \u21A9`, {
description: `\u00a0 \u2014 \u00a0\u00a0 to search for ${placeHolder}` sha: pick.commit.sha,
}, Commands.ShowCommitSearch, [gitUri, search, searchBy, goBackCommand])); commit: pick.commit,
goBackCommand: new CommandQuickPickItem({
label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to search for ${placeHolder}`
}, Commands.ShowCommitSearch, [
gitUri,
args
])
} as ShowQuickCommitDetailsCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowCommitSearchCommand'); Logger.error(ex, 'ShowCommitSearchCommand');

View File

@@ -1,34 +1,38 @@
'use strict'; 'use strict';
import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode'; import { commands, Position, Range, TextEditor, TextEditorEdit, Uri, window } from 'vscode';
import { Commands, EditorCommand } from './common'; import { Commands, EditorCommand, getCommandUri } from './common';
import { BuiltInCommands } from '../constants'; import { BuiltInCommands } from '../constants';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface ShowFileHistoryCommandArgs {
line?: number;
position?: Position;
sha?: string;
}
export class ShowFileHistoryCommand extends EditorCommand { export class ShowFileHistoryCommand extends EditorCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowFileHistory); super(Commands.ShowFileHistory);
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, position?: Position, sha?: string, line?: number) { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ShowFileHistoryCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
if (position == null) { if (args.position == null) {
// If the command is executed manually -- treat it as a click on the root lens (i.e. show blame for the whole file) // If the command is executed manually -- treat it as a click on the root lens (i.e. show blame for the whole file)
position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start; args.position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start;
} }
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
try { try {
const locations = await this.git.getLogLocations(gitUri, sha, line); const locations = await this.git.getLogLocations(gitUri, args.sha, args.line);
if (!locations) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`); if (locations === undefined) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`);
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, position, locations); return commands.executeCommand(BuiltInCommands.ShowReferences, uri, args.position, locations);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowFileHistoryCommand', 'getLogLocations'); Logger.error(ex, 'ShowFileHistoryCommand', 'getLogLocations');

View File

@@ -1,9 +1,19 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri, IGitLog } from '../gitService'; import { GitService, GitUri, IGitLog } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { BranchesQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickPicks'; import { BranchesQuickPick, BranchHistoryQuickPick, CommandQuickPickItem } from '../quickPicks';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
export interface ShowQuickBranchHistoryCommandArgs {
branch?: string;
log?: IGitLog;
maxCount?: number;
goBackCommand?: CommandQuickPickItem;
nextPageCommand?: CommandQuickPickItem;
}
export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand { export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
@@ -11,58 +21,63 @@ export class ShowQuickBranchHistoryCommand extends ActiveEditorCachedCommand {
super(Commands.ShowQuickBranchHistory); super(Commands.ShowQuickBranchHistory);
} }
async execute(editor: TextEditor, uri?: Uri, branch?: string, maxCount?: number, goBackCommand?: CommandQuickPickItem, log?: IGitLog, nextPageCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickBranchHistoryCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
const gitUri = uri && await GitUri.fromUri(uri, this.git); const gitUri = uri && await GitUri.fromUri(uri, this.git);
if (maxCount == null) { if (args.maxCount == null) {
maxCount = this.git.config.advanced.maxQuickHistory; args.maxCount = this.git.config.advanced.maxQuickHistory;
} }
let progressCancellation = branch === undefined ? undefined : BranchHistoryQuickPick.showProgress(branch); let progressCancellation = args.branch === undefined ? undefined : BranchHistoryQuickPick.showProgress(args.branch);
try { try {
const repoPath = (gitUri && gitUri.repoPath) || this.git.repoPath; const repoPath = (gitUri && gitUri.repoPath) || this.git.repoPath;
if (repoPath === undefined) return window.showWarningMessage(`Unable to show branch history`); if (repoPath === undefined) return window.showWarningMessage(`Unable to show branch history`);
if (branch === undefined) { if (args.branch === undefined) {
const branches = await this.git.getBranches(repoPath); const branches = await this.git.getBranches(repoPath);
const pick = await BranchesQuickPick.show(branches, `Show history for branch\u2026`); const pick = await BranchesQuickPick.show(branches, `Show history for branch\u2026`);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
branch = pick.branch.name; args.branch = pick.branch.name;
if (branch === undefined) return undefined; if (args.branch === undefined) return undefined;
progressCancellation = BranchHistoryQuickPick.showProgress(branch); progressCancellation = BranchHistoryQuickPick.showProgress(args.branch);
} }
if (!log) { if (args.log === undefined) {
log = await this.git.getLogForRepo(repoPath, (gitUri && gitUri.sha) || branch, maxCount); args.log = await this.git.getLogForRepo(repoPath, (gitUri && gitUri.sha) || args.branch, args.maxCount);
if (!log) return window.showWarningMessage(`Unable to show branch history`); if (args.log === undefined) return window.showWarningMessage(`Unable to show branch history`);
} }
if (progressCancellation !== undefined && progressCancellation.token.isCancellationRequested) return undefined; if (progressCancellation !== undefined && progressCancellation.token.isCancellationRequested) return undefined;
const pick = await BranchHistoryQuickPick.show(this.git, log, gitUri, branch, progressCancellation!, goBackCommand, nextPageCommand); const pick = await BranchHistoryQuickPick.show(this.git, args.log, gitUri, args.branch, progressCancellation!, args.goBackCommand, args.nextPageCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return commands.executeCommand(Commands.ShowQuickCommitDetails, new GitUri(pick.commit.uri, pick.commit), pick.commit.sha, pick.commit, // Create a command to get back to here
new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${branch} history` description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${args.branch} history`
}, Commands.ShowQuickBranchHistory, [uri, branch, maxCount, goBackCommand, log]), }, Commands.ShowQuickBranchHistory, [
log); uri,
args
]);
return commands.executeCommand(Commands.ShowQuickCommitDetails,
new GitUri(pick.commit.uri, pick.commit),
{
sha: pick.commit.sha,
commit: pick.commit,
repoLog: args.log,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickBranchHistoryCommand'); Logger.error(ex, 'ShowQuickBranchHistoryCommand');

View File

@@ -1,43 +1,50 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService'; import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, CommitDetailsQuickPick, CommitWithFileStatusQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem, CommitDetailsQuickPick, CommitWithFileStatusQuickPickItem } from '../quickPicks';
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
import * as path from 'path'; import * as path from 'path';
export interface ShowQuickCommitDetailsCommandArgs {
sha?: string;
commit?: GitCommit | GitLogCommit;
repoLog?: IGitLog;
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand { export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowQuickCommitDetails); super(Commands.ShowQuickCommitDetails);
} }
async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem, repoLog?: IGitLog) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickCommitDetailsCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
let repoPath = gitUri.repoPath; let repoPath = gitUri.repoPath;
let workingFileName = path.relative(repoPath || '', gitUri.fsPath); let workingFileName = path.relative(repoPath || '', gitUri.fsPath);
if (!sha) { if (args.sha === undefined) {
if (!editor) return undefined; if (editor === undefined) return undefined;
const blameline = editor.selection.active.line - gitUri.offset; const blameline = editor.selection.active.line - gitUri.offset;
if (blameline < 0) return undefined; if (blameline < 0) return undefined;
try { try {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return window.showWarningMessage(`Unable to show commit details. File is probably not under source control`); if (blame === undefined) return window.showWarningMessage(`Unable to show commit details. File is probably not under source control`);
sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha; args.sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha;
repoPath = blame.commit.repoPath; repoPath = blame.commit.repoPath;
workingFileName = blame.commit.fileName; workingFileName = blame.commit.fileName;
commit = blame.commit; args.commit = blame.commit;
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickCommitDetailsCommand', `getBlameForLine(${blameline})`); Logger.error(ex, 'ShowQuickCommitDetailsCommand', `getBlameForLine(${blameline})`);
@@ -46,51 +53,60 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
} }
try { try {
if (!commit || (commit.type !== 'branch' && commit.type !== 'stash')) { if (args.commit === undefined || (args.commit.type !== 'branch' && args.commit.type !== 'stash')) {
if (repoLog) { if (args.repoLog !== undefined) {
commit = repoLog.commits.get(sha!); args.commit = args.repoLog.commits.get(args.sha!);
// If we can't find the commit, kill the repoLog // If we can't find the commit, kill the repoLog
if (commit === undefined) { if (args.commit === undefined) {
repoLog = undefined; args.repoLog = undefined;
} }
} }
if (repoLog === undefined) { if (args.repoLog === undefined) {
const log = await this.git.getLogForRepo(repoPath!, sha, 2); const log = await this.git.getLogForRepo(repoPath!, args.sha, 2);
if (log === undefined) return window.showWarningMessage(`Unable to show commit details`); if (log === undefined) return window.showWarningMessage(`Unable to show commit details`);
commit = log.commits.get(sha!); args.commit = log.commits.get(args.sha!);
} }
} }
if (commit === undefined) return window.showWarningMessage(`Unable to show commit details`); if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit details`);
if (!commit.workingFileName) { if (args.commit.workingFileName === undefined) {
commit.workingFileName = workingFileName; args.commit.workingFileName = workingFileName;
} }
if (!goBackCommand) { if (args.goBackCommand === undefined) {
// Create a command to get back to the branch history // Create a command to get back to the branch history
goBackCommand = new CommandQuickPickItem({ args.goBackCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to branch history` description: `\u00a0 \u2014 \u00a0\u00a0 to branch history`
}, Commands.ShowQuickCurrentBranchHistory, [new GitUri(commit.uri, commit)]); }, Commands.ShowQuickCurrentBranchHistory, [
new GitUri(args.commit.uri, args.commit)
]);
} }
// Create a command to get back to where we are right now // Create a command to get back to where we are right now
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(git-commit) ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(git-commit) ${args.commit.shortSha}`
}, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), sha, commit, goBackCommand, repoLog]); }, Commands.ShowQuickCommitDetails, [
new GitUri(args.commit.uri, args.commit),
args
]);
const pick = await CommitDetailsQuickPick.show(this.git, commit as GitLogCommit, uri, goBackCommand, currentCommand, repoLog); const pick = await CommitDetailsQuickPick.show(this.git, args.commit as GitLogCommit, uri, args.goBackCommand, currentCommand, args.repoLog);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (!(pick instanceof CommitWithFileStatusQuickPickItem)) { if (!(pick instanceof CommitWithFileStatusQuickPickItem)) return pick.execute();
return pick.execute();
}
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, pick.gitUri, pick.sha, commit, currentCommand); return commands.executeCommand(Commands.ShowQuickCommitFileDetails,
pick.gitUri,
{
commit: args.commit,
sha: pick.sha,
goBackCommand: currentCommand
} as ShowQuickCommitFileDetailsCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickCommitDetailsCommand'); Logger.error(ex, 'ShowQuickCommitDetailsCommand');

View File

@@ -1,41 +1,48 @@
'use strict'; 'use strict';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService'; import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, CommitFileDetailsQuickPick } from '../quickPicks'; import { CommandQuickPickItem, CommitFileDetailsQuickPick } from '../quickPicks';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
import * as path from 'path'; import * as path from 'path';
export interface ShowQuickCommitFileDetailsCommandArgs {
sha?: string;
commit?: GitCommit | GitLogCommit;
fileLog?: IGitLog;
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand { export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowQuickCommitFileDetails); super(Commands.ShowQuickCommitFileDetails);
} }
async execute(editor: TextEditor, uri?: Uri, sha?: string, commit?: GitCommit | GitLogCommit, goBackCommand?: CommandQuickPickItem, fileLog?: IGitLog) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickCommitFileDetailsCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
if (!editor || !editor.document) return undefined; if (uri === undefined) return undefined;
uri = editor.document.uri;
}
let workingFileName = commit && commit.workingFileName; let workingFileName = args.commit && args.commit.workingFileName;
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (!sha) { if (args.sha === undefined) {
if (!editor) return undefined; if (editor === undefined) return undefined;
const blameline = editor.selection.active.line - gitUri.offset; const blameline = editor.selection.active.line - gitUri.offset;
if (blameline < 0) return undefined; if (blameline < 0) return undefined;
try { try {
const blame = await this.git.getBlameForLine(gitUri, blameline); const blame = await this.git.getBlameForLine(gitUri, blameline);
if (!blame) return window.showWarningMessage(`Unable to show commit file details. File is probably not under source control`); if (blame === undefined) 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; args.sha = blame.commit.isUncommitted ? blame.commit.previousSha : blame.commit.sha;
commit = blame.commit; args.commit = blame.commit;
workingFileName = path.relative(commit.repoPath, gitUri.fsPath); workingFileName = path.relative(args.commit.repoPath, gitUri.fsPath);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickCommitFileDetailsCommand', `getBlameForLine(${blameline})`); Logger.error(ex, 'ShowQuickCommitFileDetailsCommand', `getBlameForLine(${blameline})`);
@@ -44,50 +51,56 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
} }
try { try {
if (!commit || (commit.type !== 'file' && commit.type !== 'stash')) { if (args.commit === undefined || (args.commit.type !== 'file' && args.commit.type !== 'stash')) {
if (fileLog) { if (args.fileLog !== undefined) {
commit = fileLog.commits.get(sha!); args.commit = args.fileLog.commits.get(args.sha!);
// If we can't find the commit, kill the fileLog // If we can't find the commit, kill the fileLog
if (commit === undefined) { if (args.commit === undefined) {
fileLog = undefined; args.fileLog = undefined;
} }
} }
if (fileLog === undefined) { if (args.fileLog === undefined) {
commit = await this.git.getLogCommit(commit ? commit.repoPath : gitUri.repoPath, gitUri.fsPath, sha, { previous: true }); args.commit = await this.git.getLogCommit(args.commit ? args.commit.repoPath : gitUri.repoPath, gitUri.fsPath, args.sha, { previous: true });
if (commit === undefined) return window.showWarningMessage(`Unable to show commit file details`); if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit file details`);
} }
} }
if (commit === undefined) return window.showWarningMessage(`Unable to show commit file details`); if (args.commit === undefined) return window.showWarningMessage(`Unable to show commit file details`);
// Attempt to the most recent commit -- so that we can find the real working filename if there was a rename // Attempt to the most recent commit -- so that we can find the real working filename if there was a rename
commit.workingFileName = workingFileName; args.commit.workingFileName = workingFileName;
commit.workingFileName = await this.git.findWorkingFileName(commit); args.commit.workingFileName = await this.git.findWorkingFileName(args.commit);
const shortSha = sha!.substring(0, 8); const shortSha = args.sha!.substring(0, 8);
if (!goBackCommand) { if (args.goBackCommand === undefined) {
// Create a command to get back to the commit details // Create a command to get back to the commit details
goBackCommand = new CommandQuickPickItem({ args.goBackCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(git-commit) ${shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(git-commit) ${shortSha}`
}, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), sha, commit]); }, Commands.ShowQuickCommitDetails, [
new GitUri(args.commit.uri, args.commit),
{
commit: args.commit,
sha: args.sha
} as ShowQuickCommitDetailsCommandArgs
]);
} }
const pick = await CommitFileDetailsQuickPick.show(this.git, commit as GitLogCommit, uri, goBackCommand, // Create a command to get back to where we are right now
// Create a command to get back to where we are right now const currentCommand = new CommandQuickPickItem({
new CommandQuickPickItem({ label: `go back \u21A9`,
label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(file-text) ${path.basename(args.commit.fileName)} in \u00a0$(git-commit) ${shortSha}`
description: `\u00a0 \u2014 \u00a0\u00a0 to details of \u00a0$(file-text) ${path.basename(commit.fileName)} in \u00a0$(git-commit) ${shortSha}` }, Commands.ShowQuickCommitFileDetails, [
}, Commands.ShowQuickCommitFileDetails, [new GitUri(commit.uri, commit), sha, commit, goBackCommand]), new GitUri(args.commit.uri, args.commit),
fileLog); args
]);
if (!pick) return undefined; const pick = await CommitFileDetailsQuickPick.show(this.git, args.commit as GitLogCommit, uri, args.goBackCommand, currentCommand, args.fileLog);
if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return undefined; return undefined;
} }

View File

@@ -1,29 +1,37 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { ShowQuickBranchHistoryCommandArgs } from './showQuickBranchHistory';
import { GitService } from '../gitService'; import { GitService } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem } from '../quickPicks';
export interface ShowQuickCurrentBranchHistoryCommandArgs {
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedCommand { export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowQuickCurrentBranchHistory); super(Commands.ShowQuickCurrentBranchHistory);
} }
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickCurrentBranchHistoryCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to show branch history`); if (!repoPath) return window.showWarningMessage(`Unable to show branch history`);
const branch = await this.git.getBranch(repoPath); const branch = await this.git.getBranch(repoPath);
if (!branch) return undefined; if (branch === undefined) return undefined;
return commands.executeCommand(Commands.ShowQuickBranchHistory, uri, branch.name, undefined, goBackCommand); return commands.executeCommand(Commands.ShowQuickBranchHistory,
uri,
{
branch: branch.name,
goBackCommand: args.goBackCommand
} as ShowQuickBranchHistoryCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickCurrentBranchHistoryCommand'); Logger.error(ex, 'ShowQuickCurrentBranchHistoryCommand');

View File

@@ -1,52 +1,68 @@
'use strict'; 'use strict';
import { commands, Range, TextEditor, Uri, window } from 'vscode'; import { commands, Range, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri, IGitLog } from '../gitService'; import { GitService, GitUri, IGitLog } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks'; import { CommandQuickPickItem, FileHistoryQuickPick } from '../quickPicks';
import { ShowQuickCommitFileDetailsCommandArgs } from './showQuickCommitFileDetails';
import * as path from 'path'; import * as path from 'path';
export interface ShowQuickFileHistoryCommandArgs {
log?: IGitLog;
maxCount?: number;
range?: Range;
goBackCommand?: CommandQuickPickItem;
nextPageCommand?: CommandQuickPickItem;
}
export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand { export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowQuickFileHistory); super(Commands.ShowQuickFileHistory);
} }
async execute(editor: TextEditor, uri?: Uri, range?: Range, maxCount?: number, goBackCommand?: CommandQuickPickItem, log?: IGitLog, nextPageCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickFileHistoryCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri; if (uri === undefined) return commands.executeCommand(Commands.ShowQuickCurrentBranchHistory);
}
if (!uri) return commands.executeCommand(Commands.ShowQuickCurrentBranchHistory);
const gitUri = await GitUri.fromUri(uri, this.git); const gitUri = await GitUri.fromUri(uri, this.git);
if (maxCount == null) { if (args.maxCount == null) {
maxCount = this.git.config.advanced.maxQuickHistory; args.maxCount = this.git.config.advanced.maxQuickHistory;
} }
const progressCancellation = FileHistoryQuickPick.showProgress(gitUri); const progressCancellation = FileHistoryQuickPick.showProgress(gitUri);
try { try {
if (!log) { if (args.log === undefined) {
log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha, maxCount, range); args.log = await this.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha, args.maxCount, args.range);
if (!log) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`); if (args.log === undefined) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`);
} }
if (progressCancellation.token.isCancellationRequested) return undefined; if (progressCancellation.token.isCancellationRequested) return undefined;
const pick = await FileHistoryQuickPick.show(this.git, log, gitUri, progressCancellation, goBackCommand, nextPageCommand); const pick = await FileHistoryQuickPick.show(this.git, args.log, gitUri, progressCancellation, args.goBackCommand, args.nextPageCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return commands.executeCommand(Commands.ShowQuickCommitFileDetails, new GitUri(pick.commit.uri, pick.commit), pick.commit.sha, pick.commit, // Create a command to get back to where we are right now
new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(pick.commit.fileName)}${gitUri.sha ? ` from \u00a0$(git-commit) ${gitUri.shortSha}` : ''}` description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(pick.commit.fileName)}${gitUri.sha ? ` from \u00a0$(git-commit) ${gitUri.shortSha}` : ''}`
}, Commands.ShowQuickFileHistory, [uri, range, maxCount, goBackCommand, log]), }, Commands.ShowQuickFileHistory, [
log); uri,
args
]);
return commands.executeCommand(Commands.ShowQuickCommitFileDetails,
new GitUri(pick.commit.uri, pick.commit),
{
commit: pick.commit,
fileLog: args.log,
sha: pick.commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitFileDetailsCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickFileHistoryCommand'); Logger.error(ex, 'ShowQuickFileHistoryCommand');

View File

@@ -1,34 +1,34 @@
'use strict'; 'use strict';
import { TextEditor, Uri, window } from 'vscode'; import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitService } from '../gitService'; import { GitService } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, RepoStatusQuickPick } from '../quickPicks'; import { CommandQuickPickItem, RepoStatusQuickPick } from '../quickPicks';
export interface ShowQuickRepoStatusCommandArgs {
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickRepoStatusCommand extends ActiveEditorCachedCommand { export class ShowQuickRepoStatusCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.ShowQuickRepoStatus); super(Commands.ShowQuickRepoStatus);
} }
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickRepoStatusCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to show repository status`); if (!repoPath) return window.showWarningMessage(`Unable to show repository status`);
const status = await this.git.getStatusForRepo(repoPath); const status = await this.git.getStatusForRepo(repoPath);
if (!status) return window.showWarningMessage(`Unable to show repository status`); if (status === undefined) return window.showWarningMessage(`Unable to show repository status`);
const pick = await RepoStatusQuickPick.show(status, goBackCommand); const pick = await RepoStatusQuickPick.show(status, args.goBackCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return undefined; return undefined;
} }

View File

@@ -1,9 +1,14 @@
'use strict'; 'use strict';
import { commands, TextEditor, Uri, window } from 'vscode'; import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCachedCommand, Commands } from './common'; import { ActiveEditorCachedCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri } from '../gitService'; import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem, StashListQuickPick } from '../quickPicks'; import { CommandQuickPickItem, StashListQuickPick } from '../quickPicks';
import { ShowQuickCommitDetailsCommandArgs } from './showQuickCommitDetails';
export interface ShowQuickStashListCommandArgs {
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickStashListCommand extends ActiveEditorCachedCommand { export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
@@ -11,14 +16,12 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
super(Commands.ShowQuickStashList); super(Commands.ShowQuickStashList);
} }
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem) { async execute(editor: TextEditor, uri?: Uri, args: ShowQuickStashListCommandArgs = {}) {
if (!(uri instanceof Uri)) { uri = getCommandUri(uri, editor);
uri = editor && editor.document && editor.document.uri;
}
try { try {
const repoPath = await this.git.getRepoPathFromUri(uri); const repoPath = await this.git.getRepoPathFromUri(uri);
if (repoPath === undefined) return window.showWarningMessage(`Unable to show stashed changes`); if (!repoPath) return window.showWarningMessage(`Unable to show stashed changes`);
const stash = await this.git.getStashList(repoPath); const stash = await this.git.getStashList(repoPath);
if (stash === undefined) return window.showWarningMessage(`Unable to show stashed changes`); if (stash === undefined) return window.showWarningMessage(`Unable to show stashed changes`);
@@ -27,16 +30,25 @@ export class ShowQuickStashListCommand extends ActiveEditorCachedCommand {
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to stashed changes` description: `\u00a0 \u2014 \u00a0\u00a0 to stashed changes`
}, Commands.ShowQuickStashList, [uri, goBackCommand]); }, Commands.ShowQuickStashList, [
uri,
{
goBackCommand: args.goBackCommand
} as ShowQuickStashListCommandArgs
]);
const pick = await StashListQuickPick.show(this.git, stash, 'list', goBackCommand, currentCommand); const pick = await StashListQuickPick.show(this.git, stash, 'list', args.goBackCommand, currentCommand);
if (!pick) return undefined; if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) { if (pick instanceof CommandQuickPickItem) return pick.execute();
return pick.execute();
}
return commands.executeCommand(Commands.ShowQuickCommitDetails, new GitUri(pick.commit.uri, pick.commit), pick.commit.sha, pick.commit, currentCommand); return commands.executeCommand(Commands.ShowQuickCommitDetails,
new GitUri(pick.commit.uri, pick.commit),
{
commit: pick.commit,
sha: pick.commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ShowQuickStashListCommand'); Logger.error(ex, 'ShowQuickStashListCommand');

View File

@@ -6,42 +6,50 @@ import { CommitQuickPickItem, StashListQuickPick } from '../quickPicks';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem } from '../quickPicks';
export interface StashApplyCommandArgs {
confirm?: boolean;
deleteAfter?: boolean;
stashItem?: { stashName: string, message: string };
goBackCommand?: CommandQuickPickItem;
}
export class StashApplyCommand extends Command { export class StashApplyCommand extends Command {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.StashApply); super(Commands.StashApply);
} }
async execute(stashItem: { stashName: string, message: string }, confirm: boolean = true, deleteAfter: boolean = false, goBackCommand?: CommandQuickPickItem) { async execute(args: StashApplyCommandArgs = { confirm: true, deleteAfter: false }) {
if (!this.git.config.insiders) return undefined; if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined; if (!this.git.repoPath) return undefined;
if (!stashItem || !stashItem.stashName) { if (args.stashItem === undefined || args.stashItem.stashName === undefined) {
const stash = await this.git.getStashList(this.git.repoPath); const stash = await this.git.getStashList(this.git.repoPath);
if (!stash) return window.showInformationMessage(`There are no stashed changes`); if (stash === undefined) return window.showInformationMessage(`There are no stashed changes`);
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to apply stashed changes` description: `\u00a0 \u2014 \u00a0\u00a0 to apply stashed changes`
}, Commands.StashApply, [stashItem, confirm, deleteAfter, goBackCommand]); }, Commands.StashApply, [args]);
const pick = await StashListQuickPick.show(this.git, stash, 'apply', goBackCommand, currentCommand); const pick = await StashListQuickPick.show(this.git, stash, 'apply', args.goBackCommand, currentCommand);
if (!pick || !(pick instanceof CommitQuickPickItem)) return goBackCommand && goBackCommand.execute(); if (pick === undefined || !(pick instanceof CommitQuickPickItem)) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
goBackCommand = currentCommand; args.goBackCommand = currentCommand;
stashItem = pick.commit as GitStashCommit; args.stashItem = pick.commit as GitStashCommit;
} }
try { try {
if (confirm) { if (args.confirm) {
const message = stashItem.message.length > 80 ? `${stashItem.message.substring(0, 80)}\u2026` : stashItem.message; const message = args.stashItem.message.length > 80 ? `${args.stashItem.message.substring(0, 80)}\u2026` : args.stashItem.message;
const result = await window.showWarningMessage(`Apply stashed changes '${message}' to your working tree?`, { title: 'Yes, delete after applying' } as MessageItem, { title: 'Yes' } as MessageItem, { title: 'No', isCloseAffordance: true } as MessageItem); const result = await window.showWarningMessage(`Apply stashed changes '${message}' to your working tree?`, { title: 'Yes, delete after applying' } as MessageItem, { title: 'Yes' } as MessageItem, { title: 'No', isCloseAffordance: true } as MessageItem);
if (!result || result.title === 'No') return goBackCommand && goBackCommand.execute(); if (result === undefined || result.title === 'No') return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
deleteAfter = result.title !== 'Yes'; args.deleteAfter = result.title !== 'Yes';
} }
return await this.git.stashApply(this.git.repoPath, stashItem.stashName, deleteAfter); return await this.git.stashApply(this.git.repoPath, args.stashItem.stashName, args.deleteAfter);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'StashApplyCommand'); Logger.error(ex, 'StashApplyCommand');

View File

@@ -5,25 +5,37 @@ import { Command, Commands } from './common';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem } from '../quickPicks';
export interface StashDeleteCommandArgs {
confirm?: boolean;
stashItem?: { stashName: string, message: string };
goBackCommand?: CommandQuickPickItem;
}
export class StashDeleteCommand extends Command { export class StashDeleteCommand extends Command {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.StashDelete); super(Commands.StashDelete);
} }
async execute(stashItem: { stashName: string, message: string }, confirm: boolean = true, goBackCommand?: CommandQuickPickItem) { async execute(args: StashDeleteCommandArgs = { confirm: true }) {
if (!this.git.config.insiders) return undefined; if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined; if (!this.git.repoPath) return undefined;
if (!stashItem || !stashItem.stashName) return undefined;
if (args.stashItem === undefined || args.stashItem.stashName === undefined) return undefined;
if (args.confirm === undefined) {
args.confirm = true;
}
try { try {
if (confirm) { if (args.confirm) {
const message = stashItem.message.length > 80 ? `${stashItem.message.substring(0, 80)}\u2026` : stashItem.message; const message = args.stashItem.message.length > 80 ? `${args.stashItem.message.substring(0, 80)}\u2026` : args.stashItem.message;
const result = await window.showWarningMessage(`Delete stashed changes '${message}'?`, { title: 'Yes' } as MessageItem, { title: 'No', isCloseAffordance: true } as MessageItem); const result = await window.showWarningMessage(`Delete stashed changes '${message}'?`, { title: 'Yes' } as MessageItem, { title: 'No', isCloseAffordance: true } as MessageItem);
if (!result || result.title !== 'Yes') return goBackCommand && goBackCommand.execute(); if (result === undefined || result.title !== 'Yes') return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
} }
return await this.git.stashDelete(this.git.repoPath, stashItem.stashName); return await this.git.stashDelete(this.git.repoPath, args.stashItem.stashName);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'StashDeleteCommand'); Logger.error(ex, 'StashDeleteCommand');

View File

@@ -5,26 +5,37 @@ import { Command, Commands } from './common';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks'; import { CommandQuickPickItem } from '../quickPicks';
export interface StashSaveCommandArgs {
message?: string;
unstagedOnly?: boolean;
goBackCommand?: CommandQuickPickItem;
}
export class StashSaveCommand extends Command { export class StashSaveCommand extends Command {
constructor(private git: GitService) { constructor(private git: GitService) {
super(Commands.StashSave); super(Commands.StashSave);
} }
async execute(message?: string, unstagedOnly: boolean = false, goBackCommand?: CommandQuickPickItem) { async execute(args: StashSaveCommandArgs = { unstagedOnly : false }) {
if (!this.git.config.insiders) return undefined; if (!this.git.config.insiders) return undefined;
if (!this.git.repoPath) return undefined; if (!this.git.repoPath) return undefined;
if (args.unstagedOnly === undefined) {
args.unstagedOnly = false;
}
try { try {
if (message == null) { if (args.message == null) {
message = await window.showInputBox({ args.message = await window.showInputBox({
prompt: `Please provide a stash message`, prompt: `Please provide a stash message`,
placeHolder: `Stash message` placeHolder: `Stash message`
} as InputBoxOptions); } as InputBoxOptions);
if (message === undefined) return goBackCommand && goBackCommand.execute(); if (args.message === undefined) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
} }
return await this.git.stashSave(this.git.repoPath, message, unstagedOnly); return await this.git.stashSave(this.git.repoPath, args.message, args.unstagedOnly);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'StashSaveCommand'); Logger.error(ex, 'StashSaveCommand');

View File

@@ -4,21 +4,21 @@ import { BlameAnnotationController } from '../blameAnnotationController';
import { Commands, EditorCommand } from './common'; import { Commands, EditorCommand } from './common';
import { Logger } from '../logger'; import { Logger } from '../logger';
export interface ToggleBlameCommandArgs {
sha?: string;
}
export class ToggleBlameCommand extends EditorCommand { export class ToggleBlameCommand extends EditorCommand {
constructor(private annotationController: BlameAnnotationController) { constructor(private annotationController: BlameAnnotationController) {
super(Commands.ToggleBlame); super(Commands.ToggleBlame);
} }
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string): Promise<any> { async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ToggleBlameCommandArgs = {}): Promise<any> {
if (editor && editor.document && editor.document.isDirty) return undefined; if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
try { try {
if (sha) { return this.annotationController.toggleBlameAnnotation(editor, args.sha !== undefined ? args.sha : editor.selection.active.line);
return this.annotationController.toggleBlameAnnotation(editor, sha);
}
return this.annotationController.toggleBlameAnnotation(editor, editor.selection.active.line);
} }
catch (ex) { catch (ex) {
Logger.error(ex, 'ToggleBlameCommand'); Logger.error(ex, 'ToggleBlameCommand');

View File

@@ -1,11 +1,16 @@
'use strict'; 'use strict';
import { commands, Range, Uri } from 'vscode'; import { commands, Range, Uri } from 'vscode';
import { BuiltInCommands } from '../../constants'; import { BuiltInCommands } from '../../constants';
import { GitLogCommit } from '../../gitService';
export type RemoteOpenType = 'branch' | 'commit' | 'file' | 'working-file'; export type RemoteResourceType = 'branch' | 'commit' | 'file' | 'working-file';
export type RemoteResource = { type: 'branch', branch: string } |
{ type: 'commit', sha: string } |
{ type: 'file', branch?: string, commit?: GitLogCommit, fileName: string, range?: Range, sha?: string } |
{ type: 'working-file', branch?: string, fileName: string, range?: Range };
export function getNameFromRemoteOpenType(type: RemoteOpenType) { export function getNameFromRemoteResource(resource: RemoteResource) {
switch (type) { switch (resource.type) {
case 'branch': return 'Branch'; case 'branch': return 'Branch';
case 'commit': return 'Commit'; case 'commit': return 'Commit';
case 'file': return 'File'; case 'file': return 'File';
@@ -34,19 +39,16 @@ export abstract class RemoteProvider {
return commands.executeCommand(BuiltInCommands.Open, Uri.parse(url)); return commands.executeCommand(BuiltInCommands.Open, Uri.parse(url));
} }
open(type: 'branch', branch: string): Promise<{}>; open(resource: RemoteResource): Promise<{}> {
open(type: 'commit', sha: string): Promise<{}>; switch (resource.type) {
open(type: 'file', fileName: string, branch?: string, sha?: string, range?: Range): Promise<{}>;
open(type: RemoteOpenType, ...args: any[]): Promise<{}>;
open(type: RemoteOpenType, branchOrShaOrFileName: string, fileBranch?: string, fileSha?: string, fileRange?: Range): Promise<{}> {
switch (type) {
case 'branch': case 'branch':
return this.openBranch(branchOrShaOrFileName); return this.openBranch(resource.branch);
case 'commit': case 'commit':
return this.openCommit(branchOrShaOrFileName); return this.openCommit(resource.sha);
case 'file': case 'file':
return this.openFile(resource.fileName, resource.branch, resource.sha, resource.range);
case 'working-file': case 'working-file':
return this.openFile(branchOrShaOrFileName, fileBranch, fileSha, fileRange); return this.openFile(resource.fileName, resource.branch, undefined, resource.range);
} }
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Functions, Iterables, Strings } from './system'; import { Functions, Iterables, Strings } from './system';
import { CancellationToken, CodeLens, CodeLensProvider, Command, commands, DocumentSelector, Event, EventEmitter, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode'; import { CancellationToken, CodeLens, CodeLensProvider, Command, commands, DocumentSelector, Event, EventEmitter, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode';
import { Commands } from './commands'; import { Commands, DiffWithPreviousCommandArgs, ShowBlameHistoryCommandArgs, ShowFileHistoryCommandArgs, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from './commands';
import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants'; import { BuiltInCommands, DocumentSchemes, ExtensionKey } from './constants';
import { CodeLensCommand, CodeLensLocation, IConfig, ICodeLensLanguageLocation } from './configuration'; import { CodeLensCommand, CodeLensLocation, IConfig, ICodeLensLanguageLocation } from './configuration';
import { GitCommit, GitService, GitUri, IGitBlame, IGitBlameLines } from './gitService'; import { GitCommit, GitService, GitUri, IGitBlame, IGitBlameLines } from './gitService';
@@ -321,7 +321,15 @@ export class GitCodeLensProvider implements CodeLensProvider {
lens.command = { lens.command = {
title: title, title: title,
command: Commands.ShowBlameHistory, command: Commands.ShowBlameHistory,
arguments: [Uri.file(lens.uri.fsPath), lens.blameRange, position, commit && commit.sha, line] arguments: [
Uri.file(lens.uri.fsPath),
{
line,
position,
range: lens.blameRange,
sha: commit && commit.sha
} as ShowBlameHistoryCommandArgs
]
}; };
return lens; return lens;
} }
@@ -339,7 +347,14 @@ export class GitCodeLensProvider implements CodeLensProvider {
lens.command = { lens.command = {
title: title, title: title,
command: Commands.ShowFileHistory, command: Commands.ShowFileHistory,
arguments: [Uri.file(lens.uri.fsPath), position, commit && commit.sha, line] arguments: [
Uri.file(lens.uri.fsPath),
{
line,
position,
sha: commit && commit.sha
} as ShowFileHistoryCommandArgs
]
}; };
return lens; return lens;
} }
@@ -355,8 +370,10 @@ export class GitCodeLensProvider implements CodeLensProvider {
command: Commands.DiffWithPrevious, command: Commands.DiffWithPrevious,
arguments: [ arguments: [
Uri.file(lens.uri.fsPath), Uri.file(lens.uri.fsPath),
commit, {
lens.isFullRange ? undefined : lens.blameRange commit: commit,
range: lens.isFullRange ? undefined : lens.blameRange
} as DiffWithPreviousCommandArgs
] ]
}; };
return lens; return lens;
@@ -366,7 +383,12 @@ export class GitCodeLensProvider implements CodeLensProvider {
lens.command = { lens.command = {
title: title, title: title,
command: CodeLensCommand.ShowQuickCommitDetails, command: CodeLensCommand.ShowQuickCommitDetails,
arguments: [Uri.file(lens.uri.fsPath), commit === undefined ? undefined : commit.sha, commit] arguments: [
Uri.file(lens.uri.fsPath),
{
commit,
sha: commit === undefined ? undefined : commit.sha
} as ShowQuickCommitDetailsCommandArgs]
}; };
return lens; return lens;
} }
@@ -375,7 +397,12 @@ export class GitCodeLensProvider implements CodeLensProvider {
lens.command = { lens.command = {
title: title, title: title,
command: CodeLensCommand.ShowQuickCommitFileDetails, command: CodeLensCommand.ShowQuickCommitFileDetails,
arguments: [Uri.file(lens.uri.fsPath), commit === undefined ? undefined : commit.sha, commit] arguments: [
Uri.file(lens.uri.fsPath),
{
commit,
sha: commit === undefined ? undefined : commit.sha
} as ShowQuickCommitFileDetailsCommandArgs]
}; };
return lens; return lens;
} }
@@ -384,7 +411,12 @@ export class GitCodeLensProvider implements CodeLensProvider {
lens.command = { lens.command = {
title: title, title: title,
command: CodeLensCommand.ShowQuickFileHistory, command: CodeLensCommand.ShowQuickFileHistory,
arguments: [Uri.file(lens.uri.fsPath), lens.isFullRange ? undefined : lens.blameRange] arguments: [
Uri.file(lens.uri.fsPath),
{
range: lens.isFullRange ? undefined : lens.blameRange
} as ShowQuickFileHistoryCommandArgs
]
}; };
return lens; return lens;
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
// import { Iterables } from './system'; // import { Iterables } from './system';
import { CancellationToken, CodeLens, CodeLensProvider, DocumentSelector, ExtensionContext, Range, TextDocument, Uri } from 'vscode'; import { CancellationToken, CodeLens, CodeLensProvider, DocumentSelector, ExtensionContext, Range, TextDocument, Uri } from 'vscode';
import { Commands } from './commands'; import { Commands, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs } from './commands';
import { DocumentSchemes } from './constants'; import { DocumentSchemes } from './constants';
import { GitCommit, GitService, GitUri } from './gitService'; import { GitCommit, GitService, GitUri } from './gitService';
@@ -55,8 +55,10 @@ export class GitRevisionCodeLensProvider implements CodeLensProvider {
command: Commands.DiffWithWorking, command: Commands.DiffWithWorking,
arguments: [ arguments: [
Uri.file(lens.fileName), Uri.file(lens.fileName),
lens.commit, {
lens.range.start.line commit: lens.commit,
line: lens.range.start.line
} as DiffWithWorkingCommandArgs
] ]
}; };
return Promise.resolve(lens); return Promise.resolve(lens);
@@ -68,8 +70,10 @@ export class GitRevisionCodeLensProvider implements CodeLensProvider {
command: Commands.DiffWithPrevious, command: Commands.DiffWithPrevious,
arguments: [ arguments: [
Uri.file(lens.fileName), Uri.file(lens.fileName),
lens.commit, {
lens.range.start.line commit: lens.commit,
line: lens.range.start.line
} as DiffWithPreviousCommandArgs
] ]
}; };
return Promise.resolve(lens); return Promise.resolve(lens);

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
'use strict'; 'use strict';
import { Arrays, Iterables } from '../system'; import { Arrays, Iterables } from '../system';
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode'; import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands'; import { Commands, Keyboard, KeyNoopCommand, ShowCommitSearchCommandArgs, ShowQuickBranchHistoryCommandArgs } from '../commands';
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common'; import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
import { GitService, GitUri, IGitLog } from '../gitService'; import { GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
import { OpenRemotesCommandQuickPickItem } from './remotes'; import { OpenRemotesCommandQuickPickItem } from './remotes';
export class BranchHistoryQuickPick { export class BranchHistoryQuickPick {
@@ -23,17 +23,33 @@ export class BranchHistoryQuickPick {
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${branch} history` description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${branch} history`
}, Commands.ShowQuickBranchHistory, [uri, branch, log.maxCount, goBackCommand, log]); }, Commands.ShowQuickBranchHistory, [
uri,
{
branch,
log,
maxCount: log.maxCount,
goBackCommand
} as ShowQuickBranchHistoryCommandArgs
]);
const remotes = Arrays.uniqueBy(await git.getRemotes((uri && uri.repoPath) || git.repoPath), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await git.getRemotes((uri && uri.repoPath) || git.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) { if (remotes.length) {
items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, 'branch', branch, currentCommand)); items.splice(0, 0, new OpenRemotesCommandQuickPickItem(remotes, {
type: 'branch',
branch
} as RemoteResource, currentCommand));
} }
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(search) Show Commit Search`, label: `$(search) Show Commit Search`,
description: `\u00a0 \u2014 \u00a0\u00a0 search for commits by message, author, files, or commit id` description: `\u00a0 \u2014 \u00a0\u00a0 search for commits by message, author, files, or commit id`
}, Commands.ShowCommitSearch, [new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }), undefined, undefined, currentCommand])); }, Commands.ShowCommitSearch, [
new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }),
{
goBackCommand: currentCommand
} as ShowCommitSearchCommandArgs
]));
let previousPageCommand: CommandQuickPickItem | undefined = undefined; let previousPageCommand: CommandQuickPickItem | undefined = undefined;
@@ -44,9 +60,11 @@ export class BranchHistoryQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 this may take a while` description: `\u00a0 \u2014 \u00a0\u00a0 this may take a while`
}, Commands.ShowQuickBranchHistory, [ }, Commands.ShowQuickBranchHistory, [
new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }), new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }),
branch, {
0, branch,
goBackCommand maxCount: 0,
goBackCommand
} as ShowQuickBranchHistoryCommandArgs
])); ]));
} }
else { else {
@@ -55,9 +73,10 @@ export class BranchHistoryQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 shows \u00a0$(git-branch) ${branch} history` description: `\u00a0 \u2014 \u00a0\u00a0 shows \u00a0$(git-branch) ${branch} history`
}, Commands.ShowQuickBranchHistory, [ }, Commands.ShowQuickBranchHistory, [
new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }), new GitUri(Uri.file(log.repoPath), { fileName: '', repoPath: log.repoPath }),
branch, {
undefined, branch,
currentCommand goBackCommand: currentCommand
} as ShowQuickBranchHistoryCommandArgs
])); ]));
} }
@@ -69,14 +88,29 @@ export class BranchHistoryQuickPick {
const npc = new CommandQuickPickItem({ const npc = new CommandQuickPickItem({
label: `$(arrow-right) Show Next Commits`, label: `$(arrow-right) Show Next Commits`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} newer commits` description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} newer commits`
}, Commands.ShowQuickBranchHistory, [uri, branch, log.maxCount, goBackCommand, undefined, nextPageCommand]); }, Commands.ShowQuickBranchHistory, [
uri,
{
branch,
maxCount: log.maxCount,
nextPageCommand
} as ShowQuickBranchHistoryCommandArgs
]);
const last = Iterables.last(log.commits.values()); const last = Iterables.last(log.commits.values());
if (last != null) { if (last != null) {
previousPageCommand = new CommandQuickPickItem({ previousPageCommand = new CommandQuickPickItem({
label: `$(arrow-left) Show Previous Commits`, label: `$(arrow-left) Show Previous Commits`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} older commits` description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} older commits`
}, Commands.ShowQuickBranchHistory, [new GitUri(uri ? uri : last.uri, last), branch, log.maxCount, goBackCommand, undefined, npc]); }, Commands.ShowQuickBranchHistory, [
new GitUri(uri ? uri : last.uri, last),
{
branch,
maxCount: log.maxCount,
goBackCommand,
nextPageCommand: npc
} as ShowQuickBranchHistoryCommandArgs
]);
items.splice(0, 0, previousPageCommand); items.splice(0, 0, previousPageCommand);
} }

View File

@@ -1,9 +1,9 @@
'use strict'; 'use strict';
import { Arrays, Iterables } from '../system'; import { Arrays, Iterables } from '../system';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands'; import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffDirectoryCommandCommandArgs, Keyboard, KeyNoopCommand, ShowQuickCommitDetailsCommandArgs, StashApplyCommandArgs, StashDeleteCommandArgs } from '../commands';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem } from './common'; import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem } from './common';
import { getGitStatusIcon, GitCommit, GitLogCommit, GitService, GitStashCommit, GitStatusFileStatus, GitUri, IGitLog, IGitStatusFile } from '../gitService'; import { getGitStatusIcon, GitCommit, GitLogCommit, GitService, GitStashCommit, GitStatusFileStatus, GitUri, IGitLog, IGitStatusFile, RemoteResource } from '../gitService';
import { OpenRemotesCommandQuickPickItem } from './remotes'; import { OpenRemotesCommandQuickPickItem } from './remotes';
import * as moment from 'moment'; import * as moment from 'moment';
import * as path from 'path'; import * as path from 'path';
@@ -93,47 +93,93 @@ export class CommitDetailsQuickPick {
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(git-pull-request) Apply Stashed Changes`, label: `$(git-pull-request) Apply Stashed Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
}, Commands.StashApply, [commit as GitStashCommit, true, false, currentCommand])); }, Commands.StashApply, [
{
confirm: true,
deleteAfter: false,
stashItem: commit as GitStashCommit,
goBackCommand: currentCommand
} as StashApplyCommandArgs
]));
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(x) Delete Stashed Changes`, label: `$(x) Delete Stashed Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
}, Commands.StashDelete, [commit as GitStashCommit, true, currentCommand])); }, Commands.StashDelete, [
{
confirm: true,
stashItem: commit as GitStashCommit,
goBackCommand: currentCommand
} as StashDeleteCommandArgs
]));
} }
if (!stash) { if (!stash) {
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(clippy) Copy Commit ID to Clipboard`, label: `$(clippy) Copy Commit ID to Clipboard`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.shortSha}`
}, Commands.CopyShaToClipboard, [uri, commit.sha])); }, Commands.CopyShaToClipboard, [
uri,
{
sha: commit.sha
} as CopyShaToClipboardCommandArgs
]));
} }
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(clippy) Copy Message to Clipboard`, label: `$(clippy) Copy Message to Clipboard`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
}, Commands.CopyMessageToClipboard, [uri, commit.sha, commit.message])); }, Commands.CopyMessageToClipboard, [
uri,
{
message: commit.message,
sha: commit.sha
} as CopyMessageToClipboardCommandArgs
]));
if (!stash) { if (!stash) {
const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) { if (remotes.length) {
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, 'commit', commit.sha, currentCommand)); items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
type: 'commit',
sha: commit.sha
} as RemoteResource, currentCommand));
} }
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(git-compare) Directory Compare with Previous Commit`, label: `$(git-compare) Directory Compare with Previous Commit`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha || `${commit.shortSha}^`} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha || `${commit.shortSha}^`} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}`
}, Commands.DiffDirectory, [commit.uri, commit.previousSha || `${commit.sha}^`, commit.sha])); }, Commands.DiffDirectory, [
commit.uri,
{
shaOrBranch1: commit.previousSha || `${commit.sha}^`,
shaOrBranch2: commit.sha
} as DiffDirectoryCommandCommandArgs
]));
} }
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(git-compare) Directory Compare with Working Tree`, label: `$(git-compare) Directory Compare with Working Tree`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-directory) Working Tree` description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-directory) Working Tree`
}, Commands.DiffDirectory, [uri, commit.sha])); }, Commands.DiffDirectory, [
uri,
{
shaOrBranch1: commit.sha
} as DiffDirectoryCommandCommandArgs
]));
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `Changed Files`, label: `Changed Files`,
description: commit.getDiffStatus() description: commit.getDiffStatus()
}, Commands.ShowQuickCommitDetails, [uri, commit.sha, commit, goBackCommand, repoLog])); }, Commands.ShowQuickCommitDetails, [
uri,
{
commit,
repoLog,
sha: commit.sha,
goBackCommand
} as ShowQuickCommitDetailsCommandArgs
]));
items.push(new OpenCommitFilesCommandQuickPickItem(commit)); items.push(new OpenCommitFilesCommandQuickPickItem(commit));
items.push(new OpenCommitWorkingTreeFilesCommandQuickPickItem(commit)); items.push(new OpenCommitWorkingTreeFilesCommandQuickPickItem(commit));
@@ -146,9 +192,28 @@ export class CommitDetailsQuickPick {
let nextCommand: CommandQuickPickItem | (() => Promise<CommandQuickPickItem>) | undefined = undefined; let nextCommand: CommandQuickPickItem | (() => Promise<CommandQuickPickItem>) | undefined = undefined;
if (!stash) { if (!stash) {
// If we have the full history, we are good // If we have the full history, we are good
if (repoLog && !repoLog.truncated && !repoLog.sha) { if (repoLog !== undefined && !repoLog.truncated && repoLog.sha === undefined) {
previousCommand = commit.previousSha === undefined ? undefined : new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [commit.previousUri, commit.previousSha, undefined, goBackCommand, repoLog]); previousCommand = commit.previousSha === undefined
nextCommand = commit.nextSha === undefined ? undefined : new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [commit.nextUri, commit.nextSha, undefined, goBackCommand, repoLog]); ? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [
commit.previousUri,
{
repoLog,
sha: commit.previousSha,
goBackCommand
} as ShowQuickCommitDetailsCommandArgs
]);
nextCommand = commit.nextSha === undefined
? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [
commit.nextUri,
{
repoLog,
sha: commit.nextSha,
goBackCommand
} as ShowQuickCommitDetailsCommandArgs
]);
} }
else { else {
previousCommand = async () => { previousCommand = async () => {
@@ -156,7 +221,7 @@ export class CommitDetailsQuickPick {
let c = log && log.commits.get(commit.sha); let c = log && log.commits.get(commit.sha);
// If we can't find the commit or the previous commit isn't available (since it isn't trustworthy) // If we can't find the commit or the previous commit isn't available (since it isn't trustworthy)
if (!c || !c.previousSha) { if (c === undefined || c.previousSha === undefined) {
log = await git.getLogForRepo(commit.repoPath, commit.sha, git.config.advanced.maxQuickHistory); log = await git.getLogForRepo(commit.repoPath, commit.sha, git.config.advanced.maxQuickHistory);
c = log && log.commits.get(commit.sha); c = log && log.commits.get(commit.sha);
@@ -165,8 +230,17 @@ export class CommitDetailsQuickPick {
c.nextSha = commit.nextSha; c.nextSha = commit.nextSha;
} }
} }
if (!c || !c.previousSha) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [c.previousUri, c.previousSha, undefined, goBackCommand, log]); if (c === undefined || c.previousSha === undefined) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [
c.previousUri,
{
repoLog: log,
sha: c.previousSha,
goBackCommand
} as ShowQuickCommitDetailsCommandArgs
]);
}; };
nextCommand = async () => { nextCommand = async () => {
@@ -174,20 +248,29 @@ export class CommitDetailsQuickPick {
let c = log && log.commits.get(commit.sha); let c = log && log.commits.get(commit.sha);
// If we can't find the commit or the next commit isn't available (since it isn't trustworthy) // If we can't find the commit or the next commit isn't available (since it isn't trustworthy)
if (!c || !c.nextSha) { if (c === undefined || c.nextSha === undefined) {
log = undefined; log = undefined;
c = undefined; c = undefined;
// Try to find the next commit // Try to find the next commit
const nextLog = await git.getLogForRepo(commit.repoPath, commit.sha, 1, true); const nextLog = await git.getLogForRepo(commit.repoPath, commit.sha, 1, true);
const next = nextLog && Iterables.first(nextLog.commits.values()); const next = nextLog && Iterables.first(nextLog.commits.values());
if (next && next.sha !== commit.sha) { if (next !== undefined && next.sha !== commit.sha) {
c = commit; c = commit;
c.nextSha = next.sha; c.nextSha = next.sha;
} }
} }
if (!c || !c.nextSha) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [c.nextUri, c.nextSha, undefined, goBackCommand, log]); if (c === undefined || c.nextSha === undefined) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitDetails, [
c.nextUri,
{
repoLog: log,
sha: c.nextSha,
goBackCommand
} as ShowQuickCommitDetailsCommandArgs
]);
}; };
} }
} }

View File

@@ -1,9 +1,9 @@
'use strict'; 'use strict';
import { Arrays, Iterables } from '../system'; import { Arrays, Iterables } from '../system';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands'; import { Commands, CopyMessageToClipboardCommandArgs, CopyShaToClipboardCommandArgs, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs, Keyboard, KeyNoopCommand, ShowQuickCommitDetailsCommandArgs, ShowQuickCommitFileDetailsCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common'; import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, KeyCommandQuickPickItem, OpenFileCommandQuickPickItem } from './common';
import { GitBranch, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService'; import { GitBranch, GitLogCommit, GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
import { OpenRemotesCommandQuickPickItem } from './remotes'; import { OpenRemotesCommandQuickPickItem } from './remotes';
import * as moment from 'moment'; import * as moment from 'moment';
import * as path from 'path'; import * as path from 'path';
@@ -61,13 +61,25 @@ export class CommitFileDetailsQuickPick {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(git-commit) Show Commit Details`, label: `$(git-commit) Show Commit Details`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha}`
}, Commands.ShowQuickCommitDetails, [new GitUri(commit.uri, commit), commit.sha, commit, currentCommand])); }, Commands.ShowQuickCommitDetails, [
new GitUri(commit.uri, commit),
{
commit,
sha: commit.sha,
goBackCommand: currentCommand
} as ShowQuickCommitDetailsCommandArgs
]));
if (commit.previousSha) { if (commit.previousSha) {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(git-compare) Compare with Previous Commit`, label: `$(git-compare) Compare with Previous Commit`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.previousShortSha} \u00a0 $(git-compare) \u00a0 $(git-commit) ${commit.shortSha}`
}, Commands.DiffWithPrevious, [commit.uri, commit])); }, Commands.DiffWithPrevious, [
commit.uri,
{
commit
} as DiffWithPreviousCommandArgs
]));
} }
} }
@@ -75,19 +87,35 @@ export class CommitFileDetailsQuickPick {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(git-compare) Compare with Working Tree`, label: `$(git-compare) Compare with Working Tree`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-text) ${workingName}` description: `\u00a0 \u2014 \u00a0\u00a0 $(git-commit) ${commit.shortSha} \u00a0 $(git-compare) \u00a0 $(file-text) ${workingName}`
}, Commands.DiffWithWorking, [Uri.file(path.resolve(commit.repoPath, commit.workingFileName)), commit])); }, Commands.DiffWithWorking, [
Uri.file(path.resolve(commit.repoPath, commit.workingFileName)),
{
commit
} as DiffWithWorkingCommandArgs
]));
} }
if (!stash) { if (!stash) {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(clippy) Copy Commit ID to Clipboard`, label: `$(clippy) Copy Commit ID to Clipboard`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.shortSha}`
}, Commands.CopyShaToClipboard, [uri, commit.sha])); }, Commands.CopyShaToClipboard, [
uri,
{
sha: commit.sha
} as CopyShaToClipboardCommandArgs
]));
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(clippy) Copy Message to Clipboard`, label: `$(clippy) Copy Message to Clipboard`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}` description: `\u00a0 \u2014 \u00a0\u00a0 ${commit.message}`
}, Commands.CopyMessageToClipboard, [uri, commit.sha, commit.message])); }, Commands.CopyMessageToClipboard, [
uri,
{
message: commit.message,
sha: commit.sha
} as CopyMessageToClipboardCommandArgs
]));
} }
items.push(new OpenCommitFileCommandQuickPickItem(commit)); items.push(new OpenCommitFileCommandQuickPickItem(commit));
@@ -98,11 +126,19 @@ export class CommitFileDetailsQuickPick {
const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await git.getRemotes(commit.repoPath), _ => _.url, _ => !!_.provider);
if (remotes.length) { if (remotes.length) {
if (!stash) { if (!stash) {
items.push(new OpenRemotesCommandQuickPickItem(remotes, 'file', commit.fileName, undefined, commit, currentCommand)); items.push(new OpenRemotesCommandQuickPickItem(remotes, {
type: 'file',
fileName: commit.fileName,
commit
} as RemoteResource, currentCommand));
} }
if (commit.workingFileName && commit.status !== 'D') { if (commit.workingFileName && commit.status !== 'D') {
const branch = await git.getBranch(commit.repoPath || git.repoPath) as GitBranch; const branch = await git.getBranch(commit.repoPath || git.repoPath) as GitBranch;
items.push(new OpenRemotesCommandQuickPickItem(remotes, 'working-file', commit.workingFileName, branch.name, undefined, currentCommand)); items.push(new OpenRemotesCommandQuickPickItem(remotes, {
type: 'working-file',
fileName: commit.workingFileName,
branch: branch.name
} as RemoteResource, currentCommand));
} }
} }
@@ -110,14 +146,25 @@ export class CommitFileDetailsQuickPick {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(history) Show File History`, label: `$(history) Show File History`,
description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(commit.fileName)}` description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(commit.fileName)}`
}, Commands.ShowQuickFileHistory, [Uri.file(path.resolve(commit.repoPath, commit.workingFileName)), undefined, undefined, currentCommand, fileLog])); }, Commands.ShowQuickFileHistory, [
Uri.file(path.resolve(commit.repoPath, commit.workingFileName)),
{
fileLog,
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs
]));
} }
if (!stash) { if (!stash) {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `$(history) Show ${commit.workingFileName ? 'Previous ' : ''}File History`, label: `$(history) Show ${commit.workingFileName ? 'Previous ' : ''}File History`,
description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(commit.fileName)} \u00a0\u2022\u00a0 from \u00a0$(git-commit) ${commit.shortSha}` description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(commit.fileName)} \u00a0\u2022\u00a0 from \u00a0$(git-commit) ${commit.shortSha}`
}, Commands.ShowQuickFileHistory, [new GitUri(commit.uri, commit), undefined, undefined, currentCommand])); }, Commands.ShowQuickFileHistory, [
new GitUri(commit.uri, commit),
{
goBackCommand: currentCommand
} as ShowQuickFileHistoryCommandArgs
]));
} }
if (goBackCommand) { if (goBackCommand) {
@@ -128,9 +175,28 @@ export class CommitFileDetailsQuickPick {
let nextCommand: CommandQuickPickItem | (() => Promise<CommandQuickPickItem>) | undefined = undefined; let nextCommand: CommandQuickPickItem | (() => Promise<CommandQuickPickItem>) | undefined = undefined;
if (!stash) { if (!stash) {
// If we have the full history, we are good // If we have the full history, we are good
if (fileLog && !fileLog.truncated && !fileLog.sha) { if (fileLog !== undefined && !fileLog.truncated && fileLog.sha === undefined) {
previousCommand = commit.previousSha === undefined ? undefined : new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [commit.previousUri, commit.previousSha, undefined, goBackCommand, fileLog]); previousCommand = commit.previousSha === undefined
nextCommand = commit.nextSha === undefined ? undefined : new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [commit.nextUri, commit.nextSha, undefined, goBackCommand, fileLog]); ? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
commit.previousUri,
{
fileLog,
sha: commit.previousSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
]);
nextCommand = commit.nextSha === undefined
? undefined
: new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
commit.nextUri,
{
fileLog,
sha: commit.nextSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
]);
} }
else { else {
previousCommand = async () => { previousCommand = async () => {
@@ -138,13 +204,13 @@ export class CommitFileDetailsQuickPick {
let c = log && log.commits.get(commit.sha); let c = log && log.commits.get(commit.sha);
// If we can't find the commit or the previous commit isn't available (since it isn't trustworthy) // If we can't find the commit or the previous commit isn't available (since it isn't trustworthy)
if (!c || !c.previousSha) { if (c === undefined || c.previousSha === undefined) {
log = await git.getLogForFile(commit.repoPath, uri.fsPath, commit.sha, git.config.advanced.maxQuickHistory); log = await git.getLogForFile(commit.repoPath, uri.fsPath, commit.sha, git.config.advanced.maxQuickHistory);
if (log === undefined) return KeyNoopCommand; if (log === undefined) return KeyNoopCommand;
c = log && log.commits.get(commit.sha); c = log && log.commits.get(commit.sha);
// Since we exclude merge commits in file log, just grab the first returned commit // Since we exclude merge commits in file log, just grab the first returned commit
if (!c && commit.isMerge) { if (c === undefined && commit.isMerge) {
c = Iterables.first(log.commits.values()); c = Iterables.first(log.commits.values());
} }
@@ -154,8 +220,17 @@ export class CommitFileDetailsQuickPick {
c.nextFileName = commit.nextFileName; c.nextFileName = commit.nextFileName;
} }
} }
if (!c || !c.previousSha) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [c.previousUri, c.previousSha, undefined, goBackCommand, log]); if (c === undefined || c.previousSha === undefined) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
c.previousUri,
{
fileLog: log,
sha: c.previousSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
]);
}; };
nextCommand = async () => { nextCommand = async () => {
@@ -163,20 +238,29 @@ export class CommitFileDetailsQuickPick {
let c = log && log.commits.get(commit.sha); let c = log && log.commits.get(commit.sha);
// If we can't find the commit or the next commit isn't available (since it isn't trustworthy) // If we can't find the commit or the next commit isn't available (since it isn't trustworthy)
if (!c || !c.nextSha) { if (c === undefined || c.nextSha === undefined) {
log = undefined; log = undefined;
c = undefined; c = undefined;
// Try to find the next commit // Try to find the next commit
const next = await git.findNextCommit(commit.repoPath, uri.fsPath, commit.sha); const next = await git.findNextCommit(commit.repoPath, uri.fsPath, commit.sha);
if (next && next.sha !== commit.sha) { if (next !== undefined && next.sha !== commit.sha) {
c = commit; c = commit;
c.nextSha = next.sha; c.nextSha = next.sha;
c.nextFileName = next.originalFileName || next.fileName; c.nextFileName = next.originalFileName || next.fileName;
} }
} }
if (!c || !c.nextSha) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [c.nextUri, c.nextSha, undefined, goBackCommand, log]); if (c === undefined || c.nextSha === undefined) return KeyNoopCommand;
return new KeyCommandQuickPickItem(Commands.ShowQuickCommitFileDetails, [
c.nextUri,
{
fileLog: log,
sha: c.nextSha,
goBackCommand
} as ShowQuickCommitFileDetailsCommandArgs
]);
}; };
} }
} }

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
import { CancellationTokenSource, commands, Disposable, QuickPickItem, QuickPickOptions, Uri, window, workspace } from 'vscode'; import { CancellationTokenSource, commands, Disposable, QuickPickItem, QuickPickOptions, TextDocumentShowOptions, TextEditor, Uri, window, workspace } from 'vscode';
import { Commands, Keyboard, KeyboardScope, KeyMapping, openEditor } from '../commands'; import { Commands, Keyboard, Keys, KeyboardScope, KeyMapping, openEditor } from '../commands';
import { IAdvancedConfig } from '../configuration'; import { IAdvancedConfig } from '../configuration';
import { ExtensionKey } from '../constants'; import { ExtensionKey } from '../constants';
import { GitCommit, GitLogCommit, GitStashCommit } from '../gitService'; import { GitCommit, GitLogCommit, GitStashCommit } from '../gitService';
@@ -61,20 +61,45 @@ function _getInfiniteCancellablePromise(cancellation: CancellationTokenSource) {
}); });
} }
export interface QuickPickItem extends QuickPickItem {
onDidSelect?(): void;
onDidPressKey?(key: Keys): Promise<{} | undefined>;
}
export class CommandQuickPickItem implements QuickPickItem { export class CommandQuickPickItem implements QuickPickItem {
label: string; label: string;
description: string; description: string;
detail?: string | undefined; detail?: string | undefined;
protected command: Commands | undefined;
protected args: any[] | undefined;
constructor(item: QuickPickItem, protected command: Commands | undefined, protected args?: any[]) { constructor(item: QuickPickItem, args?: [Commands, any[]]);
constructor(item: QuickPickItem, command?: Commands, args?: any[]);
constructor(item: QuickPickItem, commandOrArgs?: Commands | [Commands, any[]], args?: any[]) {
if (commandOrArgs === undefined) {
this.command = undefined;
this.args = args;
}
else if (typeof commandOrArgs === 'string') {
this.command = commandOrArgs;
this.args = args;
}
else {
this.command = commandOrArgs[0];
this.args = commandOrArgs.slice(1);
}
Object.assign(this, item); Object.assign(this, item);
} }
execute(): Thenable<{} | undefined> { execute(): Promise<{} | undefined> {
if (this.command === undefined) return Promise.resolve(undefined); if (this.command === undefined) return Promise.resolve(undefined);
return commands.executeCommand(this.command, ...(this.args || [])); return commands.executeCommand(this.command, ...(this.args || [])) as Promise<{} | undefined>;
}
onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute();
} }
} }
@@ -91,12 +116,22 @@ export class OpenFileCommandQuickPickItem extends CommandQuickPickItem {
super(item, undefined, undefined); super(item, undefined, undefined);
} }
async execute(pinned: boolean = false): Promise<{} | undefined> { async execute(options?: TextDocumentShowOptions): Promise<TextEditor | undefined> {
return this.open(pinned); return openEditor(this.uri, options);
} }
async open(pinned: boolean = false): Promise<{} | undefined> { onDidSelect(): Promise<{} | undefined> {
return openEditor(this.uri, pinned); return this.execute({
preserveFocus: true,
preview: true
});
}
onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute({
preserveFocus: true,
preview: false
});
} }
} }
@@ -106,12 +141,19 @@ export class OpenFilesCommandQuickPickItem extends CommandQuickPickItem {
super(item, undefined, undefined); super(item, undefined, undefined);
} }
async execute(): Promise<{} | undefined> { async execute(options: TextDocumentShowOptions = { preserveFocus: false, preview: false }): Promise<{} | undefined> {
for (const uri of this.uris) { for (const uri of this.uris) {
await openEditor(uri, true); await openEditor(uri, options);
} }
return undefined; return undefined;
} }
async onDidPressKey(key: Keys): Promise<{} | undefined> {
return this.execute({
preserveFocus: true,
preview: false
});
}
} }
export class CommitQuickPickItem implements QuickPickItem { export class CommitQuickPickItem implements QuickPickItem {

View File

@@ -1,9 +1,9 @@
'use strict'; 'use strict';
import { Arrays, Iterables } from '../system'; import { Arrays, Iterables } from '../system';
import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode'; import { CancellationTokenSource, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard, KeyNoopCommand } from '../commands'; import { Commands, Keyboard, KeyNoopCommand, ShowQuickCurrentBranchHistoryCommandArgs, ShowQuickFileHistoryCommandArgs } from '../commands';
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common'; import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut, showQuickPickProgress } from './common';
import { GitService, GitUri, IGitLog } from '../gitService'; import { GitService, GitUri, IGitLog, RemoteResource } from '../gitService';
import { OpenRemotesCommandQuickPickItem } from './remotes'; import { OpenRemotesCommandQuickPickItem } from './remotes';
import * as path from 'path'; import * as path from 'path';
@@ -30,7 +30,13 @@ export class FileHistoryQuickPick {
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(sync) Show All Commits`, label: `$(sync) Show All Commits`,
description: `\u00a0 \u2014 \u00a0\u00a0 this may take a while` description: `\u00a0 \u2014 \u00a0\u00a0 this may take a while`
}, Commands.ShowQuickFileHistory, [Uri.file(uri.fsPath), undefined, 0, goBackCommand])); }, Commands.ShowQuickFileHistory, [
Uri.file(uri.fsPath),
{
maxCount: 0,
goBackCommand
} as ShowQuickFileHistoryCommandArgs
]));
} }
else { else {
const workingFileName = await git.findWorkingFileName(log.repoPath, path.relative(log.repoPath, uri.fsPath)); const workingFileName = await git.findWorkingFileName(log.repoPath, path.relative(log.repoPath, uri.fsPath));
@@ -40,14 +46,22 @@ export class FileHistoryQuickPick {
label: `$(history) Show File History`, label: `$(history) Show File History`,
description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(workingFileName)}` description: `\u00a0 \u2014 \u00a0\u00a0 of ${path.basename(workingFileName)}`
}, Commands.ShowQuickFileHistory, [ }, Commands.ShowQuickFileHistory, [
Uri.file(path.resolve(log.repoPath, workingFileName)), Uri.file(path.resolve(log.repoPath, workingFileName)),
undefined, {
undefined, goBackCommand: new CommandQuickPickItem({
new CommandQuickPickItem({ label: `go back \u21A9`,
label: `go back \u21A9`, description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}`
description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}` }, Commands.ShowQuickFileHistory, [
}, Commands.ShowQuickFileHistory, [uri, log.range, log.maxCount, goBackCommand, log]) uri,
])); {
log: log,
maxCount: log.maxCount,
range: log.range,
goBackCommand
} as ShowQuickFileHistoryCommandArgs
])
} as ShowQuickFileHistoryCommandArgs
]));
} }
} }
@@ -60,14 +74,28 @@ export class FileHistoryQuickPick {
const npc = new CommandQuickPickItem({ const npc = new CommandQuickPickItem({
label: `$(arrow-right) Show Next Commits`, label: `$(arrow-right) Show Next Commits`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} newer commits` description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} newer commits`
}, Commands.ShowQuickFileHistory, [uri, undefined, log.maxCount, goBackCommand, undefined, nextPageCommand]); }, Commands.ShowQuickFileHistory, [
uri,
{
maxCount: log.maxCount,
goBackCommand,
nextPageCommand
} as ShowQuickFileHistoryCommandArgs
]);
const last = Iterables.last(log.commits.values()); const last = Iterables.last(log.commits.values());
if (last != null) { if (last != null) {
previousPageCommand = new CommandQuickPickItem({ previousPageCommand = new CommandQuickPickItem({
label: `$(arrow-left) Show Previous Commits`, label: `$(arrow-left) Show Previous Commits`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} older commits` description: `\u00a0 \u2014 \u00a0\u00a0 shows ${log.maxCount} older commits`
}, Commands.ShowQuickFileHistory, [new GitUri(uri, last), undefined, log.maxCount, goBackCommand, undefined, npc]); }, Commands.ShowQuickFileHistory, [
new GitUri(uri, last),
{
maxCount: log.maxCount,
goBackCommand,
nextPageCommand: npc
} as ShowQuickFileHistoryCommandArgs
]);
index++; index++;
items.splice(0, 0, previousPageCommand); items.splice(0, 0, previousPageCommand);
@@ -80,23 +108,37 @@ export class FileHistoryQuickPick {
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}` description: `\u00a0 \u2014 \u00a0\u00a0 to history of \u00a0$(file-text) ${path.basename(uri.fsPath)}${uri.sha ? ` from \u00a0$(git-commit) ${uri.shortSha}` : ''}`
}, Commands.ShowQuickFileHistory, [uri, log.range, log.maxCount, undefined, log]); }, Commands.ShowQuickFileHistory, [
uri,
{
log,
maxCount: log.maxCount,
range: log.range
} as ShowQuickFileHistoryCommandArgs
]);
// Only show the full repo option if we are the root // Only show the full repo option if we are the root
if (!goBackCommand) { if (goBackCommand === undefined) {
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `$(history) Show Branch History`, label: `$(history) Show Branch History`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows \u00a0$(git-branch) ${branch!.name} history` description: `\u00a0 \u2014 \u00a0\u00a0 shows \u00a0$(git-branch) ${branch!.name} history`
}, Commands.ShowQuickCurrentBranchHistory, }, Commands.ShowQuickCurrentBranchHistory,
[ [
undefined, undefined,
currentCommand {
goBackCommand: currentCommand
} as ShowQuickCurrentBranchHistoryCommandArgs
])); ]));
} }
const remotes = Arrays.uniqueBy(await git.getRemotes(uri.repoPath!), _ => _.url, _ => !!_.provider); const remotes = Arrays.uniqueBy(await git.getRemotes(uri.repoPath!), _ => _.url, _ => !!_.provider);
if (remotes.length) { if (remotes.length) {
items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, 'file', uri.getRelativePath(), branch!.name, uri.sha, currentCommand)); items.splice(index++, 0, new OpenRemotesCommandQuickPickItem(remotes, {
type: 'file',
branch: branch!.name,
fileName: uri.getRelativePath(),
sha: uri.sha
} as RemoteResource, currentCommand));
} }
if (goBackCommand) { if (goBackCommand) {

View File

@@ -1,88 +1,66 @@
'use strict'; 'use strict';
import { QuickPickOptions, window } from 'vscode'; import { QuickPickOptions, window } from 'vscode';
import { Commands } from '../commands'; import { Commands, OpenInRemoteCommandArgs } from '../commands';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './common'; import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './common';
import { getNameFromRemoteOpenType, GitLogCommit, GitRemote, RemoteOpenType } from '../gitService'; import { getNameFromRemoteResource, GitLogCommit, GitRemote, RemoteResource } from '../gitService';
import * as path from 'path'; import * as path from 'path';
export class OpenRemoteCommandQuickPickItem extends CommandQuickPickItem { export class OpenRemoteCommandQuickPickItem extends CommandQuickPickItem {
private remote: GitRemote; private remote: GitRemote;
private type: RemoteOpenType; private resource: RemoteResource;
constructor(remote: GitRemote, type: RemoteOpenType, ...args: string[]) { constructor(remote: GitRemote, resource: RemoteResource) {
super({ super({
label: `$(link-external) Open ${getNameFromRemoteOpenType(type)} in ${remote.provider!.name}`, label: `$(link-external) Open ${getNameFromRemoteResource(resource)} in ${remote.provider!.name}`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider!.path}` description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider!.path}`
}, undefined, undefined); }, undefined, undefined);
this.remote = remote; this.remote = remote;
this.type = type; this.resource = resource;
this.args = args;
} }
async execute(): Promise<{}> { async execute(): Promise<{}> {
return this.remote.provider!.open(this.type, ...this.args!); return this.remote.provider!.open(this.resource);
} }
} }
export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem { export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
constructor(remotes: GitRemote[], type: 'branch', branch: string, goBackCommand?: CommandQuickPickItem); constructor(remotes: GitRemote[], resource: RemoteResource, goBackCommand?: CommandQuickPickItem) {
constructor(remotes: GitRemote[], type: 'commit', sha: string, goBackCommand?: CommandQuickPickItem); const name = getNameFromRemoteResource(resource);
constructor(remotes: GitRemote[], type: 'file', fileName: string, branch?: string, commit?: GitLogCommit, goBackCommand?: CommandQuickPickItem);
constructor(remotes: GitRemote[], type: 'file' | 'working-file', fileName: string, branch?: string, sha?: string, goBackCommand?: CommandQuickPickItem);
constructor(remotes: GitRemote[], type: RemoteOpenType, branchOrShaOrFileName: string, goBackCommandOrFileBranch?: CommandQuickPickItem | string, fileShaOrCommit?: string | GitLogCommit, goBackCommand?: CommandQuickPickItem) {
let fileBranch: string | undefined = undefined;
if (typeof goBackCommandOrFileBranch === 'string') {
fileBranch = goBackCommandOrFileBranch;
}
else if (!goBackCommand) {
goBackCommand = goBackCommandOrFileBranch;
}
const name = getNameFromRemoteOpenType(type); let description: string = '';
switch (resource.type) {
let fileSha: string | undefined = undefined;
let description: string | undefined = undefined;
let placeHolder: string | undefined = undefined;
switch (type) {
case 'branch': case 'branch':
description = `$(git-branch) ${branchOrShaOrFileName}`; description = `$(git-branch) ${resource.branch}`;
placeHolder = `open ${branchOrShaOrFileName} ${name.toLowerCase()} in\u2026`;
break; break;
case 'commit': case 'commit':
const shortSha = branchOrShaOrFileName.substring(0, 8); const shortSha = resource.sha.substring(0, 8);
description = `$(git-commit) ${shortSha}`; description = `$(git-commit) ${shortSha}`;
placeHolder = `open ${name.toLowerCase()} ${shortSha} in\u2026`;
break; break;
case 'file':
case 'working-file':
const fileName = path.basename(branchOrShaOrFileName);
if (fileShaOrCommit instanceof GitLogCommit) {
if (fileShaOrCommit.status === 'D') {
fileSha = fileShaOrCommit.previousSha;
description = `$(file-text) ${fileName} in \u00a0$(git-commit) ${fileShaOrCommit.previousShortSha} (deleted in \u00a0$(git-commit) ${fileShaOrCommit.shortSha})`; case 'file':
placeHolder = `open ${branchOrShaOrFileName} \u00a0\u2022\u00a0 ${fileShaOrCommit.previousShortSha} in\u2026`; if (resource.commit !== undefined && resource.commit instanceof GitLogCommit) {
if (resource.commit.status === 'D') {
resource.sha = resource.commit.previousSha;
description = `$(file-text) ${path.basename(resource.fileName)} in \u00a0$(git-commit) ${resource.commit.previousShortSha} (deleted in \u00a0$(git-commit) ${resource.commit.shortSha})`;
} }
else { else {
fileSha = fileShaOrCommit.sha; resource.sha = resource.commit.sha;
description = `$(file-text) ${path.basename(resource.fileName)} in \u00a0$(git-commit) ${resource.commit.shortSha}`;
description = `$(file-text) ${fileName} in \u00a0$(git-commit) ${fileShaOrCommit.shortSha}`;
placeHolder = `open ${branchOrShaOrFileName} \u00a0\u2022\u00a0 ${fileShaOrCommit.shortSha} in\u2026`;
} }
} }
else { else {
fileSha = fileShaOrCommit; const shortFileSha = resource.sha === undefined ? '' : resource.sha.substring(0, 8);
const shortFileSha = (fileSha && fileSha.substring(0, 8)) || ''; description = `$(file-text) ${path.basename(resource.fileName)}${shortFileSha ? ` in \u00a0$(git-commit) ${shortFileSha}` : ''}`;
const shaSuffix = shortFileSha ? ` \u00a0\u2022\u00a0 ${shortFileSha}` : '';
description = `$(file-text) ${fileName}${shortFileSha ? ` in \u00a0$(git-commit) ${shortFileSha}` : ''}`;
placeHolder = `open ${branchOrShaOrFileName}${shaSuffix} in\u2026`;
} }
break; break;
case 'working-file':
description = `$(file-text) ${path.basename(resource.fileName)}`;
break;
} }
const remote = remotes[0]; const remote = remotes[0];
@@ -90,7 +68,14 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
super({ super({
label: `$(link-external) Open ${name} in ${remote.provider!.name}`, label: `$(link-external) Open ${name} in ${remote.provider!.name}`,
description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider!.path} \u00a0\u2022\u00a0 ${description}` description: `\u00a0 \u2014 \u00a0\u00a0 $(repo) ${remote.provider!.path} \u00a0\u2022\u00a0 ${description}`
}, Commands.OpenInRemote, [undefined, remotes, type, [branchOrShaOrFileName, fileBranch, fileSha], goBackCommand]); }, Commands.OpenInRemote, [
undefined,
{
remotes,
resource,
goBackCommand
} as OpenInRemoteCommandArgs
]);
return; return;
} }
@@ -102,15 +87,21 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem {
super({ super({
label: `$(link-external) Open ${name} in ${provider}\u2026`, label: `$(link-external) Open ${name} in ${provider}\u2026`,
description: `\u00a0 \u2014 \u00a0\u00a0 ${description}` description: `\u00a0 \u2014 \u00a0\u00a0 ${description}`
}, Commands.OpenInRemote, [undefined, remotes, type, [branchOrShaOrFileName, fileBranch, fileSha], goBackCommand]); }, Commands.OpenInRemote, [
undefined,
{
remotes,
resource,
goBackCommand
} as OpenInRemoteCommandArgs
]);
} }
} }
export class RemotesQuickPick { export class RemotesQuickPick {
static async show(remotes: GitRemote[], placeHolder: string, type: RemoteOpenType, args: string[], goBackCommand?: CommandQuickPickItem): Promise<OpenRemoteCommandQuickPickItem | CommandQuickPickItem | undefined> { static async show(remotes: GitRemote[], placeHolder: string, resource: RemoteResource, goBackCommand?: CommandQuickPickItem): Promise<OpenRemoteCommandQuickPickItem | CommandQuickPickItem | undefined> {
const items = remotes.map(_ => new OpenRemoteCommandQuickPickItem(_, resource)) as (OpenRemoteCommandQuickPickItem | CommandQuickPickItem)[];
const items = remotes.map(_ => new OpenRemoteCommandQuickPickItem(_, type, ...args)) as (OpenRemoteCommandQuickPickItem | CommandQuickPickItem)[];
if (goBackCommand) { if (goBackCommand) {
items.splice(0, 0, goBackCommand); items.splice(0, 0, goBackCommand);
@@ -118,12 +109,11 @@ export class RemotesQuickPick {
// const scope = await Keyboard.instance.beginScope({ left: goBackCommand }); // const scope = await Keyboard.instance.beginScope({ left: goBackCommand });
const pick = await window.showQuickPick(items, const pick = await window.showQuickPick(items, {
{ placeHolder: placeHolder,
placeHolder: placeHolder, ignoreFocusOut: getQuickPickIgnoreFocusOut()
ignoreFocusOut: getQuickPickIgnoreFocusOut() } as QuickPickOptions);
} as QuickPickOptions); if (pick === undefined) return undefined;
if (!pick) return undefined;
// await scope.dispose(); // await scope.dispose();

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode';
import { Commands, Keyboard } from '../commands'; import { Commands, Keyboard, OpenChangedFilesCommandArgs, ShowQuickBranchHistoryCommandArgs, ShowQuickRepoStatusCommandArgs, ShowQuickStashListCommandArgs } from '../commands';
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem } from './common'; import { CommandQuickPickItem, getQuickPickIgnoreFocusOut, OpenFileCommandQuickPickItem } from './common';
import { GitService, GitStatusFile, GitUri, IGitStatus } from '../gitService'; import { GitService, GitStatusFile, GitUri, IGitStatus } from '../gitService';
import * as path from 'path'; import * as path from 'path';
@@ -36,7 +36,12 @@ export class OpenStatusFilesCommandQuickPickItem extends CommandQuickPickItem {
label: `$(file-symlink-file) Open Changed Files`, label: `$(file-symlink-file) Open Changed Files`,
description: '' description: ''
//detail: `Opens all of the changed files in the repository` //detail: `Opens all of the changed files in the repository`
}, Commands.OpenChangedFiles, [undefined, uris]); }, Commands.OpenChangedFiles, [
undefined,
{
uris
} as OpenChangedFilesCommandArgs
]);
} }
} }
@@ -72,7 +77,12 @@ export class RepoStatusQuickPick {
const currentCommand = new CommandQuickPickItem({ const currentCommand = new CommandQuickPickItem({
label: `go back \u21A9`, label: `go back \u21A9`,
description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${status.branch} status` description: `\u00a0 \u2014 \u00a0\u00a0 to \u00a0$(git-branch) ${status.branch} status`
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand]); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]);
if (hasStaged) { if (hasStaged) {
let index = 0; let index = 0;
@@ -81,7 +91,12 @@ export class RepoStatusQuickPick {
items.splice(unstagedIndex, 0, new CommandQuickPickItem({ items.splice(unstagedIndex, 0, new CommandQuickPickItem({
label: `Unstaged Files`, label: `Unstaged Files`,
description: unstagedStatus description: unstagedStatus
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand])); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]));
items.splice(unstagedIndex, 0, new OpenStatusFilesCommandQuickPickItem(files.filter(_ => _.status !== 'D' && _.staged), { items.splice(unstagedIndex, 0, new OpenStatusFilesCommandQuickPickItem(files.filter(_ => _.status !== 'D' && _.staged), {
label: `\u00a0\u00a0\u00a0\u00a0 $(file-symlink-file) Open Staged Files`, label: `\u00a0\u00a0\u00a0\u00a0 $(file-symlink-file) Open Staged Files`,
@@ -97,13 +112,23 @@ export class RepoStatusQuickPick {
items.splice(index++, 0, new CommandQuickPickItem({ items.splice(index++, 0, new CommandQuickPickItem({
label: `Staged Files`, label: `Staged Files`,
description: stagedStatus description: stagedStatus
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand])); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]));
} }
else if (files.some(_ => !_.staged)) { else if (files.some(_ => !_.staged)) {
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `Unstaged Files`, label: `Unstaged Files`,
description: unstagedStatus description: unstagedStatus
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand])); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]));
} }
if (files.length) { if (files.length) {
@@ -117,13 +142,23 @@ export class RepoStatusQuickPick {
items.push(new CommandQuickPickItem({ items.push(new CommandQuickPickItem({
label: `No changes in the working tree`, label: `No changes in the working tree`,
description: '' description: ''
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand])); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]));
} }
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(repo-push) Show Stashed Changes`, label: `$(repo-push) Show Stashed Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 shows stashed changes in the repository` description: `\u00a0 \u2014 \u00a0\u00a0 shows stashed changes in the repository`
}, Commands.ShowQuickStashList, [new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath }), currentCommand])); }, Commands.ShowQuickStashList, [
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath }),
{
goBackCommand: currentCommand
} as ShowQuickStashListCommandArgs
]));
if (status.upstream && status.state.ahead) { if (status.upstream && status.state.ahead) {
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
@@ -131,9 +166,12 @@ export class RepoStatusQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 shows commits in \u00a0$(git-branch) ${status.branch} but not \u00a0$(git-branch) ${status.upstream}` description: `\u00a0 \u2014 \u00a0\u00a0 shows commits in \u00a0$(git-branch) ${status.branch} but not \u00a0$(git-branch) ${status.upstream}`
}, Commands.ShowQuickBranchHistory, [ }, Commands.ShowQuickBranchHistory, [
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.upstream}..${status.branch}` }), new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.upstream}..${status.branch}` }),
status.branch, 0, currentCommand {
]) branch: status.branch,
); maxCount: 0,
goBackCommand: currentCommand
} as ShowQuickBranchHistoryCommandArgs
]));
} }
if (status.upstream && status.state.behind) { if (status.upstream && status.state.behind) {
@@ -142,16 +180,24 @@ export class RepoStatusQuickPick {
description: `\u00a0 \u2014 \u00a0\u00a0 shows commits in \u00a0$(git-branch) ${status.upstream} but not \u00a0$(git-branch) ${status.branch}${status.sha ? ` (since \u00a0$(git-commit) ${status.sha.substring(0, 8)})` : ''}` description: `\u00a0 \u2014 \u00a0\u00a0 shows commits in \u00a0$(git-branch) ${status.upstream} but not \u00a0$(git-branch) ${status.branch}${status.sha ? ` (since \u00a0$(git-commit) ${status.sha.substring(0, 8)})` : ''}`
}, Commands.ShowQuickBranchHistory, [ }, Commands.ShowQuickBranchHistory, [
new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.branch}..${status.upstream}` }), new GitUri(Uri.file(status.repoPath), { fileName: '', repoPath: status.repoPath, sha: `${status.branch}..${status.upstream}` }),
status.upstream, 0, currentCommand {
]) branch: status.upstream,
); maxCount: 0,
goBackCommand: currentCommand
} as ShowQuickBranchHistoryCommandArgs
]));
} }
if (status.upstream && !status.state.ahead && !status.state.behind) { if (status.upstream && !status.state.ahead && !status.state.behind) {
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(git-branch) ${status.branch} is up-to-date with \u00a0$(git-branch) ${status.upstream}`, label: `$(git-branch) ${status.branch} is up-to-date with \u00a0$(git-branch) ${status.upstream}`,
description: '' description: ''
}, Commands.ShowQuickRepoStatus, [undefined, goBackCommand])); }, Commands.ShowQuickRepoStatus, [
undefined,
{
goBackCommand
} as ShowQuickRepoStatusCommandArgs
]));
} }

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { Iterables } from '../system'; import { Iterables } from '../system';
import { QuickPickOptions, window } from 'vscode'; import { QuickPickOptions, window } from 'vscode';
import { Commands, Keyboard } from '../commands'; import { Commands, Keyboard, StashSaveCommandArgs } from '../commands';
import { GitService, IGitStash } from '../gitService'; import { GitService, IGitStash } from '../gitService';
import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks'; import { CommandQuickPickItem, CommitQuickPickItem, getQuickPickIgnoreFocusOut } from '../quickPicks';
@@ -14,12 +14,22 @@ export class StashListQuickPick {
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(repo-push) Stash Unstaged Changes`, label: `$(repo-push) Stash Unstaged Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 stashes only unstaged changes` description: `\u00a0 \u2014 \u00a0\u00a0 stashes only unstaged changes`
}, Commands.StashSave, [undefined, true, currentCommand])); }, Commands.StashSave, [
{
unstagedOnly: true,
goBackCommand: currentCommand
} as StashSaveCommandArgs
]));
items.splice(0, 0, new CommandQuickPickItem({ items.splice(0, 0, new CommandQuickPickItem({
label: `$(repo-push) Stash Changes`, label: `$(repo-push) Stash Changes`,
description: `\u00a0 \u2014 \u00a0\u00a0 stashes all changes` description: `\u00a0 \u2014 \u00a0\u00a0 stashes all changes`
}, Commands.StashSave, [undefined, undefined, currentCommand])); }, Commands.StashSave, [
{
unstagedOnly: false,
goBackCommand: currentCommand
} as StashSaveCommandArgs
]));
} }
if (goBackCommand) { if (goBackCommand) {