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';
import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorTracker } from '../activeEditorTracker';
import { ActiveEditorCommand, Commands } from './common';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { TextEditorComparer, UriComparer } from '../comparers';
import { GitService } from '../gitService';
import { Logger } from '../logger';
export interface CloseUnchangedFilesCommandArgs {
uris?: Uri[];
}
export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.CloseUnchangedFiles);
}
async execute(editor: TextEditor, uri?: Uri, uris?: Uri[]) {
if (!(uri instanceof Uri)) {
uri = editor && editor.document && editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: CloseUnchangedFilesCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
if (!uris) {
if (args.uris === undefined) {
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);
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();
@@ -35,7 +37,7 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
do {
if (editor !== undefined) {
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 (active === undefined) {
active = editor;

View File

@@ -1,5 +1,5 @@
'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 { Logger } from '../logger';
import { Telemetry } from '../telemetry';
@@ -48,6 +48,12 @@ export const 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 const CommandContext = {
CanToggleCodeLens: 'gitlens:canToggleCodeLens' as CommandContext,
@@ -140,12 +146,16 @@ export abstract class ActiveEditorCachedCommand extends ActiveEditorCommand {
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 {
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);
return window.showTextDocument(document, (window.activeTextEditor && window.activeTextEditor.viewColumn) || 1, true);
return window.showTextDocument(document, { ...defaults, ...(options || {}) });
}
catch (ex) {
Logger.error(ex, 'openEditor');

View File

@@ -1,40 +1,43 @@
'use strict';
import { Iterables } from '../system';
import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
import { copy } from 'copy-paste';
export interface CopyMessageToClipboardCommandArgs {
message?: string;
sha?: string;
}
export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.CopyMessageToClipboard);
}
async execute(editor: TextEditor, uri?: Uri, sha?: string, message?: string): Promise<any> {
if (!(uri instanceof Uri)) {
uri = editor && editor.document && editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: CopyMessageToClipboardCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
try {
// 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;
const log = await this.git.getLogForRepo(this.git.repoPath, undefined, 1);
if (!log) return undefined;
message = Iterables.first(log.commits.values()).message;
copy(message);
args.message = Iterables.first(log.commits.values()).message;
copy(args.message);
return undefined;
}
const gitUri = await GitUri.fromUri(uri, this.git);
if (!message) {
if (!sha) {
if (editor && editor.document && editor.document.isDirty) return undefined;
if (args.message === undefined) {
if (args.sha === undefined) {
if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const line = (editor && editor.selection.active.line) || gitUri.offset;
const blameline = line - gitUri.offset;
@@ -46,7 +49,7 @@ export class CopyMessageToClipboardCommand extends ActiveEditorCommand {
if (blame.commit.isUncommitted) return undefined;
sha = blame.commit.sha;
args.sha = blame.commit.sha;
if (!gitUri.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
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;
message = commit.message;
args.message = commit.message;
}
copy(message);
copy(args.message);
return undefined;
}
catch (ex) {

View File

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

View File

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

View File

@@ -1,51 +1,63 @@
'use strict';
import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants';
import { DiffWithPreviousCommandArgs } from './diffWithPrevious';
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
import * as path from 'path';
export interface DiffLineWithPreviousCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.DiffLineWithPrevious);
}
async execute(editor: TextEditor): Promise<any>;
async execute(editor: TextEditor, uri: Uri): Promise<any>;
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: DiffLineWithPreviousCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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 (editor && editor.document && editor.document.isDirty) return undefined;
if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
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;
try {
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 (!gitUri.sha || gitUri.sha === commit.sha) {
return commands.executeCommand(Commands.DiffWithPrevious, new GitUri(uri, commit), undefined, line);
if (gitUri.sha === undefined || gitUri.sha === args.commit.sha) {
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 (commit.isUncommitted) {
uri = commit.uri;
commit = new GitCommit(commit.type, commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message);
line = (blame.line.line + 1) + gitUri.offset;
return commands.executeCommand(Commands.DiffWithWorking, uri, commit, line);
if (args.commit.isUncommitted) {
uri = args.commit.uri;
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);
args.line = (blame.line.line + 1) + gitUri.offset;
return commands.executeCommand(Commands.DiffWithWorking, uri, {
commit: args.commit,
line: args.line,
showOptions: args.showOptions
} as DiffWithWorkingCommandArgs);
}
}
catch (ex) {
@@ -57,11 +69,17 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
try {
const [rhs, lhs] = await Promise.all([
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
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' });
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: args.line, at: 'center' });
}
catch (ex) {
Logger.error(ex, 'DiffWithPreviousLineCommand', 'getVersionedFile');

View File

@@ -1,41 +1,44 @@
'use strict';
import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
export interface DiffLineWithWorkingCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.DiffLineWithWorking);
}
async execute(editor: TextEditor): Promise<any>;
async execute(editor: TextEditor, uri: Uri): Promise<any>;
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: DiffLineWithWorkingCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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 (editor && editor.document && editor.document.isDirty) return undefined;
if (args.commit === undefined || GitService.isUncommitted(args.commit.sha)) {
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;
try {
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 (commit.isUncommitted) {
commit = new GitCommit(commit.type, commit.repoPath, commit.previousSha!, commit.previousFileName!, commit.author, commit.date, commit.message);
line = blame.line.line + 1 + gitUri.offset;
if (args.commit.isUncommitted) {
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);
args.line = blame.line.line + 1 + gitUri.offset;
}
}
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';
import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants';
import { GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
import * as path from 'path';
export interface DiffWithBranchCommandArgs {
line?: number;
showOptions?: TextDocumentShowOptions;
goBackCommand?: CommandQuickPickItem;
}
export class DiffWithBranchCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.DiffWithBranch);
}
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: DiffWithBranchCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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);
if (gitUri.repoPath === undefined) return undefined;
const branches = await this.git.getBranches(gitUri.repoPath);
const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, goBackCommand);
if (!pick) return undefined;
const pick = await BranchesQuickPick.show(branches, `Compare ${path.basename(gitUri.fsPath)} to \u2026`, args.goBackCommand);
if (pick === undefined) return undefined;
if (pick instanceof CommandQuickPickItem) {
return pick.execute();
}
if (pick instanceof CommandQuickPickItem) return pick.execute();
const branch = pick.branch.name;
if (!branch) return undefined;
if (branch === undefined) return undefined;
try {
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) {
Logger.error(ex, 'DiffWithBranchCommand', 'getVersionedFile');

View File

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

View File

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

View File

@@ -1,34 +1,35 @@
'use strict';
// import { Iterables } from '../system';
import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands } from './common';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { BuiltInCommands } from '../constants';
import { GitCommit, GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
import * as path from 'path';
export interface DiffWithWorkingCommandArgs {
commit?: GitCommit;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffWithWorkingCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.DiffWithWorking);
}
async execute(editor: TextEditor): Promise<any>;
async execute(editor: TextEditor, uri: Uri): Promise<any>;
async execute(editor: TextEditor, uri?: Uri, commit?: GitCommit, line?: number): Promise<any> {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: DiffWithWorkingCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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);
try {
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`);
args.commit = await this.git.getLogCommit(gitUri.repoPath, gitUri.fsPath, gitUri.sha, { firstIfMissing: true });
if (args.commit === undefined) return window.showWarningMessage(`Unable to open compare. File is probably not under source control`);
}
catch (ex) {
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;
try {
const compare = await this.git.getVersionedFile(commit.repoPath, commit.uri.fsPath, 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' });
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(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) {
Logger.error(ex, 'DiffWithWorkingCommand', 'getVersionedFile');

View File

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

View File

@@ -1,33 +1,35 @@
'use strict';
import { TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, openEditor } from './common';
import { TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorCommand, Commands, getCommandUri, openEditor } from './common';
import { GitService } from '../gitService';
import { Logger } from '../logger';
export interface OpenChangedFilesCommandArgs {
uris?: Uri[];
}
export class OpenChangedFilesCommand extends ActiveEditorCommand {
constructor(private git: GitService) {
super(Commands.OpenChangedFiles);
}
async execute(editor: TextEditor, uri?: Uri, uris?: Uri[]) {
if (!(uri instanceof Uri)) {
uri = editor && editor.document && editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: OpenChangedFilesCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
if (!uris) {
if (args.uris === undefined) {
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);
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) {
await openEditor(uri, true);
for (const uri of args.uris) {
await openEditor(uri, { preserveFocus: true, preview: false } as TextDocumentShowOptions);
}
return undefined;

View File

@@ -1,9 +1,10 @@
'use strict';
import { Arrays } from '../system';
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 { Logger } from '../logger';
import { OpenInRemoteCommandArgs } from './openInRemote';
export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
@@ -12,24 +13,21 @@ export class OpenCommitInRemoteCommand extends ActiveEditorCommand {
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
if ((editor && editor.document && editor.document.isDirty) || !uri) return undefined;
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
if (editor !== undefined && editor.document !== undefined && editor.document.isDirty) return undefined;
const gitUri = await GitUri.fromUri(uri, this.git);
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 {
const blameline = line - gitUri.offset;
if (blameline < 0) return undefined;
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;
// 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);
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) {
Logger.error(ex, 'OpenCommitInRemoteCommand');

View File

@@ -1,9 +1,10 @@
'use strict';
import { Arrays } from '../system';
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 { Logger } from '../logger';
import { OpenInRemoteCommandArgs } from './openInRemote';
export class OpenFileInRemoteCommand extends ActiveEditorCommand {
@@ -12,12 +13,8 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri) {
if (!(uri instanceof Uri)) {
if (!editor || !editor.document) return undefined;
uri = editor.document.uri;
}
if (!uri) return undefined;
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
const gitUri = await GitUri.fromUri(uri, this.git);
if (!gitUri.repoPath) return undefined;
@@ -26,8 +23,18 @@ export class OpenFileInRemoteCommand extends ActiveEditorCommand {
try {
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 }));
return commands.executeCommand(Commands.OpenInRemote, uri, remotes, 'file', [gitUri.getRelativePath(), branch === undefined ? 'Current' : branch.name, gitUri.sha, range]);
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, {
resource: {
type: 'file',
branch: branch === undefined ? 'Current' : branch.name,
fileName: gitUri.getRelativePath(),
range: range,
sha: gitUri.sha
},
remotes
} as OpenInRemoteCommandArgs);
}
catch (ex) {
Logger.error(ex, 'OpenFileInRemoteCommand');

View File

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

View File

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

View File

@@ -1,35 +1,40 @@
'use strict';
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 { GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
export interface ShowBlameHistoryCommandArgs {
line?: number;
position?: Position;
range?: Range;
sha?: string;
}
export class ShowBlameHistoryCommand extends EditorCommand {
constructor(private git: GitService) {
super(Commands.ShowBlameHistory);
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, range?: Range, position?: Position, sha?: string, line?: number) {
if (!(uri instanceof Uri)) {
if (!editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ShowBlameHistoryCommandArgs = {}) {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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)
range = editor.document.validateRange(new Range(0, 0, 1000000, 1000000));
position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start;
args.range = editor.document.validateRange(new Range(0, 0, 1000000, 1000000));
args.position = editor.document.validateRange(new Range(0, 0, 0, 1000000)).start;
}
const gitUri = await GitUri.fromUri(uri, this.git);
try {
const locations = await this.git.getBlameLocations(gitUri, range, sha, line);
if (!locations) return window.showWarningMessage(`Unable to show blame history. File is probably not under source control`);
const locations = await this.git.getBlameLocations(gitUri, args.range, args.sha, args.line);
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) {
Logger.error(ex, 'ShowBlameHistoryCommand', 'getBlameLocations');

View File

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

View File

@@ -1,34 +1,38 @@
'use strict';
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 { GitService, GitUri } from '../gitService';
import { Logger } from '../logger';
export interface ShowFileHistoryCommandArgs {
line?: number;
position?: Position;
sha?: string;
}
export class ShowFileHistoryCommand extends EditorCommand {
constructor(private git: GitService) {
super(Commands.ShowFileHistory);
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, position?: Position, sha?: string, line?: number) {
if (!(uri instanceof Uri)) {
if (!editor.document) return undefined;
uri = editor.document.uri;
}
async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ShowFileHistoryCommandArgs = {}) {
uri = getCommandUri(uri, editor);
if (uri === undefined) return undefined;
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)
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);
try {
const locations = await this.git.getLogLocations(gitUri, sha, line);
if (!locations) return window.showWarningMessage(`Unable to show file history. File is probably not under source control`);
const locations = await this.git.getLogLocations(gitUri, args.sha, args.line);
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) {
Logger.error(ex, 'ShowFileHistoryCommand', 'getLogLocations');

View File

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

View File

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

View File

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

View File

@@ -1,29 +1,37 @@
'use strict';
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 { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks';
export interface ShowQuickCurrentBranchHistoryCommandArgs {
goBackCommand?: CommandQuickPickItem;
}
export class ShowQuickCurrentBranchHistoryCommand extends ActiveEditorCachedCommand {
constructor(private git: GitService) {
super(Commands.ShowQuickCurrentBranchHistory);
}
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem) {
if (!(uri instanceof Uri)) {
uri = editor && editor.document && editor.document.uri;
}
async execute(editor: TextEditor, uri?: Uri, args: ShowQuickCurrentBranchHistoryCommandArgs = {}) {
uri = getCommandUri(uri, editor);
try {
const repoPath = await this.git.getRepoPathFromUri(uri);
if (!repoPath) return window.showWarningMessage(`Unable to show branch history`);
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) {
Logger.error(ex, 'ShowQuickCurrentBranchHistoryCommand');

View File

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

View File

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

View File

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

View File

@@ -6,42 +6,50 @@ import { CommitQuickPickItem, StashListQuickPick } from '../quickPicks';
import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks';
export interface StashApplyCommandArgs {
confirm?: boolean;
deleteAfter?: boolean;
stashItem?: { stashName: string, message: string };
goBackCommand?: CommandQuickPickItem;
}
export class StashApplyCommand extends Command {
constructor(private git: GitService) {
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.repoPath) return undefined;
if (!stashItem || !stashItem.stashName) {
if (args.stashItem === undefined || args.stashItem.stashName === undefined) {
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({
label: `go back \u21A9`,
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);
if (!pick || !(pick instanceof CommitQuickPickItem)) return goBackCommand && goBackCommand.execute();
const pick = await StashListQuickPick.show(this.git, stash, 'apply', args.goBackCommand, currentCommand);
if (pick === undefined || !(pick instanceof CommitQuickPickItem)) return args.goBackCommand === undefined ? undefined : args.goBackCommand.execute();
goBackCommand = currentCommand;
stashItem = pick.commit as GitStashCommit;
args.goBackCommand = currentCommand;
args.stashItem = pick.commit as GitStashCommit;
}
try {
if (confirm) {
const message = stashItem.message.length > 80 ? `${stashItem.message.substring(0, 80)}\u2026` : stashItem.message;
if (args.confirm) {
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);
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) {
Logger.error(ex, 'StashApplyCommand');

View File

@@ -5,25 +5,37 @@ import { Command, Commands } from './common';
import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks';
export interface StashDeleteCommandArgs {
confirm?: boolean;
stashItem?: { stashName: string, message: string };
goBackCommand?: CommandQuickPickItem;
}
export class StashDeleteCommand extends Command {
constructor(private git: GitService) {
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.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 {
if (confirm) {
const message = stashItem.message.length > 80 ? `${stashItem.message.substring(0, 80)}\u2026` : stashItem.message;
if (args.confirm) {
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);
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) {
Logger.error(ex, 'StashDeleteCommand');

View File

@@ -5,26 +5,37 @@ import { Command, Commands } from './common';
import { Logger } from '../logger';
import { CommandQuickPickItem } from '../quickPicks';
export interface StashSaveCommandArgs {
message?: string;
unstagedOnly?: boolean;
goBackCommand?: CommandQuickPickItem;
}
export class StashSaveCommand extends Command {
constructor(private git: GitService) {
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.repoPath) return undefined;
if (args.unstagedOnly === undefined) {
args.unstagedOnly = false;
}
try {
if (message == null) {
message = await window.showInputBox({
if (args.message == null) {
args.message = await window.showInputBox({
prompt: `Please provide a stash message`,
placeHolder: `Stash message`
} 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) {
Logger.error(ex, 'StashSaveCommand');

View File

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