From f9275a8e1a25493be6a223afdfc1a2fb1d3f82f9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 26 Jun 2017 23:55:39 -0400 Subject: [PATCH] Reworks command structure with context --- src/commands/common.ts | 92 +++++++++++++++++++++++++++++++++++++++- src/commands/diffWithPrevious.ts | 26 +++++++++--- 2 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/commands/common.ts b/src/commands/common.ts index 12698c2..2faf198 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -1,5 +1,5 @@ 'use strict'; -import { commands, Disposable, TextDocumentShowOptions, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode'; +import { commands, Disposable, SourceControlResourceGroup, SourceControlResourceState, TextDocumentShowOptions, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode'; import { Logger } from '../logger'; import { Telemetry } from '../telemetry'; @@ -86,6 +86,51 @@ export function getCommandUri(uri?: Uri, editor?: TextEditor): Uri | undefined { return editor.document.uri; } +export interface ScmGroupsCommandContext { + type: 'scm-groups'; + scmResourceGroups: SourceControlResourceGroup[]; +} + +export interface ScmStatesCommandContext { + type: 'scm-states'; + scmResourceStates: SourceControlResourceState[]; +} + +export interface UnknownCommandContext { + type: 'unknown'; + editor?: TextEditor; +} + +export interface UriCommandContext { + type: 'uri'; + editor?: TextEditor; + uri: Uri; +} + +export type CommandContext = ScmGroupsCommandContext | ScmStatesCommandContext | UnknownCommandContext | UriCommandContext; + +function isScmResourceGroup(group: any): group is SourceControlResourceGroup { + if (group === undefined) return false; + + return (group as SourceControlResourceGroup).id !== undefined && (group.handle !== undefined || (group as SourceControlResourceGroup).label !== undefined || (group as SourceControlResourceGroup).resourceStates !== undefined); +} + +function isScmResourceState(state: any): state is SourceControlResourceState { + if (state === undefined) return false; + + return (state as SourceControlResourceState).resourceUri !== undefined; +} + +function isTextEditor(editor: any): editor is TextEditor { + if (editor === undefined) return false; + + return editor.id !== undefined && ((editor as TextEditor).edit !== undefined || (editor as TextEditor).document !== undefined); +} + +export interface Command { + run?(context: CommandContext, ...args: any[]): any; +} + export abstract class Command extends Disposable { private _disposable: Disposable; @@ -101,6 +146,51 @@ export abstract class Command extends Disposable { protected _execute(...args: any[]): any { Telemetry.trackEvent(this.command); + + if (typeof this.run === 'function') { + let editor: TextEditor | undefined = undefined; + + let firstArg = args[0]; + if (firstArg === undefined || isTextEditor(firstArg)) { + editor = firstArg; + args = args.slice(1); + firstArg = args[0]; + } + + if (firstArg instanceof Uri) { + const [uri, ...rest] = args; + return this.run({ type: 'uri', editor: editor, uri: uri }, ...rest); + } + + if (isScmResourceState(firstArg)) { + const states = []; + let count = 0; + for (const arg of args) { + if (!isScmResourceState(arg)) break; + + count++; + states.push(arg); + } + + return this.run({ type: 'scm-states', scmResourceStates: states }, ...args.slice(count)); + } + + if (isScmResourceGroup(firstArg)) { + const groups = []; + let count = 0; + for (const arg of args) { + if (!isScmResourceGroup(arg)) break; + + count++; + groups.push(arg); + } + + return this.run({ type: 'scm-groups', scmResourceGroups: groups }, ...args.slice(count)); + } + + return this.run({ type: 'unknown', editor: editor }, ...args); + } + return this.execute(...args); } diff --git a/src/commands/diffWithPrevious.ts b/src/commands/diffWithPrevious.ts index 6b1b210..0fd5e14 100644 --- a/src/commands/diffWithPrevious.ts +++ b/src/commands/diffWithPrevious.ts @@ -1,7 +1,7 @@ 'use strict'; import { Iterables } from '../system'; import { commands, Range, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode'; -import { ActiveEditorCommand, Commands, getCommandUri } from './common'; +import { ActiveEditorCommand, CommandContext, Commands, getCommandUri } from './common'; import { BuiltInCommands, GlyphChars } from '../constants'; import { DiffWithWorkingCommandArgs } from './diffWithWorking'; import { GitCommit, GitService, GitUri } from '../gitService'; @@ -22,15 +22,27 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand { super(Commands.DiffWithPrevious); } - async execute(editor: TextEditor, uri?: Uri, args: DiffWithPreviousCommandArgs = {}): Promise { + async run(context: CommandContext, args: DiffWithPreviousCommandArgs = {}): Promise { + // Since we can change the args and they could be cached -- make a copy + switch (context.type) { + case 'uri': + return this.execute(context.editor, context.uri, { ...args }); + case 'scm-states': + const resource = context.scmResourceStates[0]; + return this.execute(undefined, resource.resourceUri, { ...args }); + case 'scm-groups': + return undefined; + default: + return this.execute(context.editor, undefined, { ...args }); + } + } + + async execute(editor: TextEditor | undefined, uri?: Uri, args: DiffWithPreviousCommandArgs = {}): Promise { uri = getCommandUri(uri, editor); if (uri === undefined) return undefined; - if (args.commit !== undefined && args.commit.type !== 'file') { - args.line = 0; - } - else { - args.line = args.line || (editor === undefined ? 0 : editor.selection.active.line); + if (args.line === undefined) { + args.line = editor === undefined ? 0 : editor.selection.active.line; } if (args.commit === undefined || args.commit.type !== 'file' || args.range !== undefined) {